remember — је функција у Jetpack Compose-у која омогућава чување вредности између рекомпозиција, спречавајући ресетовање стања при сваком поновном покретању Composable функције. Без remember, све променљиве декларисане унутар функције би се ресетовале при сваком ажурирању UI-ја, чинећи стање нестабилним и бескорисним. Према Google Android Developers, 2026, правилна употреба remember-а је основа исправног управљања стањем у декларативном UI-ју.
Главне тачке
remember — је уграђена функција Jetpack Compose-а из пакета androidx.compose.runtime која креира објекат који чува своју вредност између узастопних позива Composable функције. Технички, remember ради са слотовима — посебним меморијским ћелијама додељеним за сваку позицију позива функције у UI стаблу. Док год функција остаје у саставу композиције (није уклоњена кроз if услов), remember ће враћати сачувану вредност при свакој рекомпозицији.
Синтакса remember-а је једноставна: у витичастим заградама се наводи блок израчунавања почетне вредности. Блок се извршава само једном — при првој композицији функције. Све наредне рекомпозиције враћају већ сачувану вредност, не позивајући блок поново. Међутим, ако је наведен кључ (параметар key), блок се поново извршава при промени кључа, што омогућава поновно израчунавање вредности на основу улазних података.
remember није Kotlin магија — то је једноставна функција са параметром key и ламбдом за израчунавање. Њена унутрашња имплементација користи Composer за читање и писање у слотове. Kotlin компајлер, видевши позив remember-а, генерише код који приступа тренутном CompositionContext-у и управља слотовима. То значи да се remember може позивати само унутар Composable функције или друге функције у контексту композиције.
У Jetpack Compose-у постоје три главне варијанте remember-а, свака са својом наменом. Основни remember чува вредност само у меморији тренутног процеса — при ротацији екрана (config change) Compose поново креира Composition и све remember вредности се ресетују. За чување података при променама конфигурације и заустављању процеса користи се rememberSaveable.
rememberSaveable серијализује вредност у Bundle кроз механизам SavedStateHandle или Parcelable. Ово омогућава преживљавање ротације екрана, позива „Не чувај активности" и чак привременог свођења апликације. Међутим, rememberSaveable намеће ограничења на тип података који се чувају: они морају бити примитиви, Parcelable, Serializable или подржавати Saver конвертер.
derivedStateOf — није механизам чувања, већ оптимизација. Креира State чија се вредност израчунава на основу других State објеката. derivedStateOf реагује на промене изворних стања, али прерачунава вредност само када постоје претплатници. Ако тренутна рекомпозиција не чита derivedStateOf, прорачун се не извршава, што штеди ресурсе при честим, али никоме потребним ажурирањима.
@Composable
fun RememberVariants() {
// 1. Основни remember: траје до напуштања композиције
val createdAt = remember { System.currentTimeMillis() }
// 2. rememberSaveable: преживљава ротацију екрана
var username by rememberSaveable { mutableStateOf("") }
// 3. derivedStateOf: израчунава се само када је потребно
val isButtonVisible = remember {
derivedStateOf { username.length() > 3 }
}
Text("Креирано: $createdAt")
TextField(value = username, onValueChange = { username = it })
if (isButtonVisible.value) {
Text("Дугме ће бити приказано")
}
}
Избор између remember-а и rememberSaveable-а зависи од тога колико је критично чување података при променама конфигурације. За привремена стања чији губитак при ротацији није важан (анимација, тренутна позиција скроловања, стање фокуса) — довољан је обичан remember. За критичне податке (текст у форми, изабрани елементи, поља за потврду) — користите rememberSaveable.
Перформансе rememberSaveable-а су ниже од обичног remember-а, јер захтевају серијализацију у Bundle. Користите rememberSaveable само за податке који заиста морају да преживе поновно креирање Activity-ја. За све остало — обичан remember. Претерана употреба rememberSaveable-а доводи до успоравања при ротацијама екрана и пребацивању између апликација.
Ако радите са класама које не подржавају Parcelable или Serializable, користите Saver — конвертер који одређује како да сачува и врати објекат. Saver је описан паром ламбди: save (претвара објекат у сачувани тип) и restore (враћа објекат из сачуваних података). Стандардни Saver је већ имплементиран за mutableStateListOf и mutableStateMapOf.
| Карактеристика | remember | rememberSaveable |
|---|---|---|
| Чување при рекомпозицији | Да | Да |
| Чување при ротацији | Не | Да |
| Чување при заустављању процеса | Не | Да |
| Захтеви за тип | Било који | Parcelable, Serializable, Saver |
| Перформансе | Високе | Средње |
Размотримо типичан сценарио — екран за уређивање профила, где се remember користи за више намена: чување стања поља форме, израчунавање изведених вредности и кеширање скупих операција.
data class ProfileUiState(
val name: String = "",
val bio: String = "",
val isSaving: Boolean = false
)
@Composable
fun ProfileEditor() {
var state by rememberSaveable { mutableStateOf(ProfileUiState()) }
val isValid = remember {
derivedStateOf { state.name.isNotBlank() && state.bio.length() <= 500 }
}
val bioWarning = remember(state.bio) {
if (state.bio.length() > 400) {
"${500 - state.bio.length} chars left"
} else null
}
Column(modifier = Modifier.padding(16.dp)) {
OutlinedTextField(
value = state.name,
onValueChange = { state = state.copy(name = it) },
label = { Text("Име") }
)
OutlinedTextField(
value = state.bio,
onValueChange = { state = state.copy(bio = it) },
label = { Text("О нама") }
)
bioWarning?.let { Text(it, color = MaterialTheme.colorScheme.error) }
Button(onClick = { /* save */ },
enabled = isValid.value) {
Text("Сачувај")
}
}
}
У примеру, стање се чува кроз rememberSaveable — при ротацији екрана текст неће нестати. isValid се израчунава кроз derivedStateOf, што спречава непотребне прорачуне при рекомпозицијама. bioWarning користи remember са кључем bio — ово је скуп прорачун (опционо, за демонстрацију) који се прерачунава само при промени bio-а, а не при свакој рекомпозицији.
Изведена стања (derived state) су вредности које се израчунавају из других State објеката. Уместо да их рачунате при свакој рекомпозицији и трошите CPU на идентичне резултате, remember са derivedStateOf израчунава вредност само при промени извора. Ово је посебно корисно за филтрирање, сортирање и агрегацију података.
remember са кључевима (remember(key) { calculation }) — други механизам оптимизације. Ако се кључ није променио од претходне рекомпозиције, блок израчунавања се не извршава и враћа се кеширана вредност. Ово је згодно за кеширање објеката чије је креирање скупо: форматирање датума, парсирање JSON-а, креирање великих непроменљивих колекција.
@Composable
fun SearchResults(allItems: List<Item>, query: String) {
// derivedStateOf: филтер се поново израчунава само када се улазни подаци промене
val filtered = remember {
derivedStateOf {
allItems.filter { it.title.contains(query, true) }
}
}
// remember са кључем: форматирана статистика се поново израчунава само при промени упита
val statsText = remember(query) {
"Results for query \"$query\": ${filtered.value.size}"
}
Text(statsText)
LazyColumn {
items(filtered.value, key = { it.id }) { item ->
Text(item.title)
}
}
}
filtered — је derivedStateOf који се аутоматски прерачунава при промени allItems или query. statsText користи remember(query) — скупо форматирање ниске се извршава само при промени претраге. Комбинација derivedStateOf и remember-а са кључевима даје максималне перформансе: изведено стање се рачуна само када је потребно, а сложени објекти се кеширају до промене кључа.
Често постављана питања
Не, remember — је функција из пакета compose.runtime која захтева CompositionContext. Може се позвати само унутар @Composable функције или унутар друге функције позване из Composable-а. За чување података ван композиције користите ViewModel.
Без кључа, remember израчунава блок само једном — при првој композицији. Све наредне рекомпозиције враћају сачувану вредност. Ако треба да прерачунавате вредност при промени података, обавезно их наведите као кључ: remember(data) { compute(data) }.
Не постоји директно ресетовање remember-а. Једини начин је да уклоните функцију из састава композиције (на пример, сакривањем кроз if услов) и затим је поново прикажете. При поновном уласку, блок remember-а ће се поново извршити, креирајући нову почетну вредност.
remember чува стање у слоту Composable функције и живи док је функција у композицији. ViewModel живи док живи lifecycle екрана. ViewModel се чува при ротацији и користи се за пословну логику. remember — за локално UI стање које није потребно ван једне функције.
Да, remember исправно ради у @Preview Composable функцијама, јер Preview креира потпуни CompositionContext. Међутим, rememberSaveable можда неће исправно радити у Preview-ју, јер SavedStateHandle може недостајати у окружењу прегледа.
Резиме
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође