remember — este o funcție în Jetpack Compose care permite păstrarea unei valori între recompoziții, prevenind resetarea stării la fiecare repornire a funcției Composable. Fără remember, toate variabilele declarate în interiorul funcției s-ar reseta la fiecare actualizare a UI, făcând starea instabilă și inutilă. Conform Google Android Developers, 2026, utilizarea corectă a remember este baza gestionării corecte a stării în UI declarativ.
Puncte cheie
remember — este o funcție încorporată Jetpack Compose din pachetul androidx.compose.runtime care creează un obiect ce își păstrează valoarea între apelurile succesive ale funcției Composable. Tehnic, remember lucrează cu sloturi — celule speciale de memorie alocate pentru fiecare poziție de apel a funcției în arborele UI. Cât timp funcția rămâne în compoziție (nu este eliminată printr-o condiție if), remember va returna valoarea salvată la fiecare recompoziție.
Sintaxa remember este simplă: în acolade se specifică blocul de calcul al valorii inițiale. Blocul se execută o singură dată — la prima compoziție a funcției. Toate recompozițiile ulterioare returnează valoarea deja salvată, fără a reexecuta blocul. Totuși, dacă este specificată o cheie (parametrul key), blocul se reexecută la modificarea cheii, permițând recalcularea valorii pe baza datelor de intrare.
remember nu este magie Kotlin — este o funcție simplă cu parametrul key și o lambda de calcul. Implementarea sa internă folosește Composer pentru citirea și scrierea în sloturi. Compilatorul Kotlin, văzând un apel remember, generează cod care accesează CompositionContext-ul curent și gestionează sloturile. Aceasta înseamnă că remember poate fi apelat doar în interiorul unei funcții Composable sau a unei alte funcții în contextul compoziției.
În Jetpack Compose există trei variante principale ale remember, fiecare cu scopul său. Remember de bază păstrează valoarea doar în memoria procesului curent — la rotirea ecranului (config change), Compose re creează Composition și toate valorile remember sunt resetate. Pentru păstrarea datelor la modificări de configurare și oprirea procesului se folosește rememberSaveable.
rememberSaveable serializează valoarea în Bundle prin mecanismul SavedStateHandle sau Parcelable. Acest lucru permite supraviețuirea rotirii ecranului, apelului „Nu păstra activități" și chiar minimizării temporare a aplicației. Totuși, rememberSaveable impune restricții asupra tipului de date păstrate: acestea trebuie să fie primitive, Parcelable, Serializable sau să suporte convertorul Saver.
derivedStateOf — nu este un mecanism de păstrare, ci o optimizare. Creează un State a cărui valoare este calculată pe baza altor obiecte State. derivedStateOf reacționează la modificările stărilor sursă, dar recalculează valoarea doar când există abonați. Dacă recompoziția curentă nu citește derivedStateOf, calculul nu se execută, economisind resurse la actualizări frecvente dar inutile.
@Composable
fun RememberVariants() {
// 1. Remember de bază: persistă până la ieșirea din compoziție
val createdAt = remember { System.currentTimeMillis() }
// 2. rememberSaveable: supraviețuiește rotirii ecranului
var username by rememberSaveable { mutableStateOf("") }
// 3. derivedStateOf: calculat doar când este necesar
val isButtonVisible = remember {
derivedStateOf { username.length() > 3 }
}
Text("Creat: $createdAt")
TextField(value = username, onValueChange = { username = it })
if (isButtonVisible.value) {
Text("Butonul va fi afișat")
}
}
Alegerea între remember și rememberSaveable depinde de cât de critică este păstrarea datelor la modificări de configurare. Pentru stări temporare a căror pierdere la rotire nu este importantă (animație, poziția curentă de scroll, starea focusului) — este suficient remember obișnuit. Pentru date critice (text în formular, elemente selectate, checkboxuri) — folosiți rememberSaveable.
Performanța rememberSaveable este mai scăzută decât a remember obișnuit, deoarece necesită serializare în Bundle. Folosiți rememberSaveable doar pentru datele care trebuie să supraviețuiască recreării Activity. Pentru orice altceva — remember simplu. Utilizarea excesivă a rememberSaveable duce la încetiniri la rotirea ecranului și la comutarea între aplicații.
Dacă lucrați cu clase care nu suportă Parcelable sau Serializable, folosiți Saver — un convertor care definește cum să salvați și să restaurați un obiect. Saver este descris de o pereche de lambda: save (transformă obiectul într-un tip salvat) și restore (restaurează obiectul din datele salvate). Saver-ul standard este deja implementat pentru mutableStateListOf și mutableStateMapOf.
| Caracteristică | remember | rememberSaveable |
|---|---|---|
| Păstrare la recompoziție | Da | Da |
| Păstrare la rotire | Nu | Da |
| Păstrare la oprirea procesului | Nu | Da |
| Cerințe de tip | Oricare | Parcelable, Serializable, Saver |
| Performanță | Ridicată | Medie |
Să analizăm un scenariu tipic — ecranul de editare a profilului, unde remember este folosit pentru mai multe scopuri: păstrarea stării câmpurilor formularului, calcularea valorilor derivate și stocarea în cache a operațiilor costisitoare.
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("Nume") }
)
OutlinedTextField(
value = state.bio,
onValueChange = { state = state.copy(bio = it) },
label = { Text("Despre") }
)
bioWarning?.let { Text(it, color = MaterialTheme.colorScheme.error) }
Button(onClick = { /* save */ },
enabled = isValid.value) {
Text("Salvare")
}
}
}
În exemplu, starea este salvată prin rememberSaveable — la rotirea ecranului textul nu va dispărea. isValid este calculat prin derivedStateOf, ceea ce previne calculele inutile la recompoziții. bioWarning folosește remember cu cheia bio — acesta este un calcul costisitor (opțional, pentru demonstrație) care se recalculează doar la modificarea bio, nu la fiecare recompoziție.
Stările derivate (derived state) sunt valori calculate din alte obiecte State. În loc să le calculați la fiecare recompoziție și să irosiți CPU pe rezultate identice, remember cu derivedStateOf calculează valoarea doar la modificarea surselor. Acest lucru este util în special pentru filtrare, sortare și agregare a datelor.
remember cu chei (remember(key) { calculation }) — un alt mecanism de optimizare. Dacă cheia nu s-a schimbat de la recompoziția anterioară, blocul de calcul nu se execută și se returnează valoarea din cache. Acest lucru este util pentru stocarea în cache a obiectelor a căror creare este costisitoare: formatarea datelor, parsarea JSON, crearea de colecții imutabile mari.
@Composable
fun SearchResults(allItems: List<Item>, query: String) {
// derivedStateOf: filtrul se recalculează doar când intrările se modifică
val filtered = remember {
derivedStateOf {
allItems.filter { it.title.contains(query, true) }
}
}
// remember cu cheie: statistici formatate recalculate doar la modificarea interogării
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 — este un derivedStateOf care se recalculează automat la modificarea allItems sau query. statsText folosește remember(query) — formatarea costisitoare a șirului se execută doar la schimbarea interogării de căutare. Combinația derivedStateOf și remember cu chei oferă performanță maximă: starea derivată se calculează doar când este necesar, iar obiectele complexe sunt stocate în cache până la modificarea cheii.
Întrebări frecvente
Nu, remember — este o funcție din pachetul compose.runtime care necesită CompositionContext. Poate fi apelată doar în interiorul unei funcții @Composable sau în interiorul unei alte funcții apelate din Composable. Pentru păstrarea datelor în afara compoziției, folosiți ViewModel.
Fără cheie, remember calculează blocul o singură dată — la prima compoziție. Toate recompozițiile ulterioare returnează valoarea salvată. Dacă trebuie să recalculați valoarea la modificarea datelor, specificați-le ca cheie: remember(data) { compute(data) }.
Nu există o resetare directă a remember. Singura modalitate este să scoateți funcția din compoziție (de exemplu, ascunzând-o printr-o condiție if) și apoi să o afișați din nou. La reintrare, blocul remember se va executa din nou, creând o nouă valoare inițială.
remember stochează starea în slotul funcției Composable și trăiește cât timp funcția este în compoziție. ViewModel trăiește cât timp trăiește lifecycle-ul ecranului. ViewModel se păstrează la rotire și este folosit pentru logica de business. remember — pentru starea UI locală care nu este necesară în afara unei singure funcții.
Da, remember funcționează corect în funcțiile @Preview Composable, deoarece Preview creează un CompositionContext complet. Totuși, rememberSaveable poate să nu funcționeze corect în Preview, deoarece SavedStateHandle poate lipsi în mediul de previzualizare.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și