Interview QuestionPractical QuestionFollow-up Questions

Stable and Unstable Types in Jetpack Compose

skydovesJaewoong Eum (skydoves)||8 min read

Stable and Unstable Types in Jetpack Compose

Jetpack Compose uses the stability of a composable's parameters to decide whether it can skip recomposition when the parent recomposes. A stable type is one whose changes Compose can reliably detect through equality checks. An unstable type is one where Compose cannot guarantee that the value has not changed, forcing it to recompose the composable unconditionally. Understanding this distinction is fundamental to avoiding unnecessary recomposition and maintaining smooth UI performance. By the end of this lesson, you will be able to:

  • Define what makes a type stable or unstable in Compose's type system.
  • Explain how parameter stability determines whether a composable can be skipped during recomposition.
  • Identify common unstable types including var properties and standard Kotlin collections.
  • Describe how MutableState qualifies as stable through observable mutation.
  • Apply stability principles to reduce unnecessary recomposition in a composable hierarchy.

What Makes a Type Stable

A type is stable if Compose can determine whether two instances represent the same value through equality comparison. There are two categories:

Immutable types have all val properties of stable types. Once created, their observable state cannot change. All Kotlin primitives, String, and data classes composed entirely of val properties of stable types fall into this category.

Observable mutable types can change, but they notify Compose when they do. MutableState<T> is the primary example. Compose tracks reads and writes to MutableState and schedules recomposition when the value changes. The mutability is controlled and observable, so Compose can still make skip decisions.

What Makes a Type Unstable

A type is unstable if Compose cannot guarantee that its value has not changed between recompositions. Common causes include:

  • Data classes with var properties that are not backed by Compose State.
  • Properties of other unstable types.
  • Standard Kotlin collections (List, Map, Set) because Compose cannot verify their immutability or track internal changes.

When a composable receives an unstable parameter, Compose cannot safely skip it. Even if the value has not actually changed, Compose must recompose the function because it cannot prove the value is the same.

Skipping Behavior

When a parent composable recomposes, Compose evaluates each child's parameters:

data class UserProfile(val id: Int, val name: String)

@Composable
fun UserProfileView(profile: UserProfile) {
    Column {
        Text("ID: ${profile.id}")
        Text("Name: ${profile.name}")
    }
}

@Composable
fun ParentScreen() {
    var user by remember {
        mutableStateOf(UserProfile(1, "Alice"))
    }
    var counter by remember { mutableStateOf(0) }

    Column {
        UserProfileView(profile = user)
        Text("Counter: $counter")
        Button(onClick = { counter++ }) {
            Text("Increment")
        }
    }
}

This interview continues for subscribers

Subscribe to Dove Letter for full access to exclusive interviews about Android and Kotlin development.

Become a Sponsor