Interview QuestionPractical QuestionFollow-up Questions

Recomposition in Jetpack Compose

skydovesJaewoong Eum (skydoves)||9 min read

Recomposition in Jetpack Compose

In Jetpack Compose, recomposition is the process that updates the UI when observable state changes. It is a central part of Compose's reactive programming model and one of the key mechanisms in the composition lifecycle. While the initial composition builds the UI tree for the first time, recomposition selectively re-executes composable functions that depend on changed state. This allows Compose to update only the necessary parts of the UI without redrawing everything. By the end of this lesson, you will be able to:

  • Explain how recomposition fits within the three Compose phases.
  • Describe how the runtime tracks state reads to determine which composables to re-execute.
  • Identify what triggers recomposition and what does not.
  • Understand how recomposition scoping affects which composables re-execute.
  • Recognize common patterns that cause unnecessary recomposition.
  • Use debugging tools to measure and reduce recomposition counts.

Where Recomposition Fits in Compose Phases

Jetpack Compose UI rendering consists of three primary phases:

  1. Composition: Building the UI tree by executing composable functions. This produces a tree of LayoutNode instances that represent the UI structure.
  2. Layout: Measuring each node and assigning its position within the parent constraints.
  3. Drawing: Rendering the final pixels to the canvas based on the measured and positioned nodes.

Recomposition is a re-execution of the Composition phase for specific parts of the tree. When a state change triggers recomposition, the runtime re-executes only the affected composable functions, updates the node tree, and then the full Layout and Drawing phases run for the changed subtree.

How the Runtime Tracks State Reads

Compose tracks state reads during the execution of composable functions using its snapshot system. When a composable reads a MutableState value, the runtime records which composable scope accessed that state. When the state value changes, the runtime knows exactly which scopes need to re-execute:

@Composable
fun Counter() {
    var count by remember { mutableStateOf(0) }

    Button(onClick = { count++ }) {
        Text("Count: $count")
    }
}

In this example, the Counter composable reads count. When the button is clicked and count changes, the runtime schedules Counter for recomposition. During re-execution, the Text composable receives the new value and the UI updates. Composables that do not read the changed state are skipped entirely.

What Triggers Recomposition

Recomposition is triggered when a State object that was read during a previous composition changes its value. The primary state holders that trigger recomposition are:

  • mutableStateOf() and its variants (mutableIntStateOf, mutableFloatStateOf)
  • derivedStateOf() when the computed value changes
  • StateFlow collected via collectAsState() or collectAsStateWithLifecycle()

Importantly, recomposition is not triggered by changes to regular variables, non state backed properties, or objects that are not read through Compose's snapshot system. If you modify a plain var inside a composable, the runtime has no way to detect the change and will not schedule re-execution.

This interview continues for subscribers

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

Become a Sponsor