100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Kotlin

State and remember

Understand how Compose tracks mutable values across recompositions using the remember function, and why state that isn't remembered gets lost.

State ManagementBeginner8 min readJul 8, 2026
Analogies

State and remember

A composable function can be called again and again — every time the UI needs to update, Compose re-executes the function body, a process called recomposition. Ordinary local variables declared inside a composable are re-initialized on every call, so a plain var counter = 0 would silently reset to zero on every recomposition, making it useless for tracking anything across UI updates. The remember function solves this by storing a value in the Composition itself, keyed to the call site, so the value survives recomposition as long as the composable stays in the same position in the UI tree.

🏏

Cricket analogy: A commentator who re-reads the day's opening team sheet from scratch every time they speak would forget the current score entirely; remember is like keeping a running scorebook that persists across every over instead of resetting to zero each time.

How remember Ties a Value to the Composition

Internally, remember stores its value in a slot table associated with the composable's position in the tree. On the first call, the lambda you pass to remember runs and its result is cached. On subsequent recompositions, Compose skips re-running that lambda and simply returns the cached value — unless you pass keys to remember(key1, key2) { ... }, in which case a change in any key forces the value to be recalculated. This is different from a field on a ViewModel: remembered state lives only as long as the composable remains part of the composition, so it is lost on configuration changes unless combined with rememberSaveable.

🏏

Cricket analogy: remember's slot table is like a scorer keeping the innings total pinned to a specific page in the scorebook — they only recalculate the total from scratch on the first ball, and every ball after just reads the cached figure unless the innings itself changes (a new key).

kotlin
@Composable
fun ExpandableCard(title: String, body: String) {
    var expanded by remember { mutableStateOf(false) }

    Column(
        modifier = Modifier
            .fillMaxWidth()
            .clickable { expanded = !expanded }
            .padding(16.dp)
    ) {
        Text(text = title, style = MaterialTheme.typography.titleMedium)
        if (expanded) {
            Text(
                text = body,
                style = MaterialTheme.typography.bodyMedium,
                modifier = Modifier.padding(top = 8.dp)
            )
        }
    }
}

remember vs rememberSaveable

remember alone does not survive a configuration change such as a screen rotation, because the Activity (and with it the whole Composition) is destroyed and recreated. rememberSaveable, by contrast, writes its value into the same Bundle-based saved-instance-state mechanism used by the View system, so simple types (String, Int, Boolean, Parcelable) survive rotation automatically. For complex objects, you supply a custom Saver that knows how to serialize and restore the value.

🏏

Cricket analogy: remember alone is like a scorer's chalk marks on a portable board that get wiped clean if the board is knocked over and reset (rotation); rememberSaveable is like writing the score into the official paper scorebook that survives the board being knocked over.

kotlin
@Composable
fun SurveyScreen() {
    var selectedRating by rememberSaveable { mutableStateOf(0) }

    Column {
        Text("Rate your experience: $selectedRating")
        Row {
            (1..5).forEach { star ->
                IconButton(onClick = { selectedRating = star }) {
                    Icon(
                        imageVector = if (star <= selectedRating) Icons.Filled.Star else Icons.Outlined.Star,
                        contentDescription = "Rate $star stars"
                    )
                }
            }
        }
    }
}

A helpful mental model: remember is like a sticky note attached to a specific spot in the UI tree — it survives as long as that spot exists, but a whole new sheet of paper (a fresh Activity after rotation) means the sticky note is gone too, unless it was written with rememberSaveable's more durable ink.

Calling remember conditionally — for example inside an if block that only sometimes executes — can break Compose's slot-table position tracking and cause state to be lost or mixed up between composables. remember (like all Compose APIs) must be called unconditionally, in the same order, on every recomposition.

  • Plain local variables reset on every recomposition; remember preserves a value across recompositions by storing it in the Composition's slot table.
  • remember { ... } only re-evaluates its initializer once, unless you pass keys that change.
  • remember does not survive configuration changes like rotation; rememberSaveable does, using the Bundle-based saved-instance-state mechanism.
  • Complex types need a custom Saver to work with rememberSaveable.
  • remember must be called unconditionally and in the same order every recomposition, never inside conditional branches.
  • Remembered state is scoped to the composable's position, not shared globally like a ViewModel field.

Practice what you learned

Was this page helpful?

Topics covered

#Kotlin#AndroidWithJetpackComposeStudyNotes#MobileDevelopment#StateAndRemember#State#Remember#Ties#Value#StudyNotes#SkillVeris