Skip to content

Jetpack Compose

Jetpack Compose interview guide

Compose interviews test whether you understand state ownership and effects, not whether you remember every annotation.

The Senior Signal (book, from $59)

Jetpack Compose: what matters most

A senior Jetpack Compose interview answer should begin with state ownership and unidirectional data flow. Explain what state belongs in the composable, screen model, saved state or durable data layer. Recomposition is normal; expensive or incorrect work during recomposition is the problem. Side-effect APIs connect composition to work with a lifetime, and their keys define when that work restarts. Stability affects skip behaviour but should be measured before it is optimised. Cover lifecycle-aware collection, derived state, list identity, process death, testing and interoperability with Views. The strongest answer links a Compose API to the invariant it protects and explains what happens when navigation, configuration or asynchronous work changes underneath the screen.

State and identity

Describe the source of truth, the event path and the lifetime of remembered state. Use stable keys for items whose identity survives position changes.

  • Local presentation state
  • Hoisted screen state
  • Saved state after process death
  • Durable repository data
  • Derived values
  • Stable list identity

Effects are lifecycle contracts

LaunchedEffect, DisposableEffect and rememberCoroutineScope serve different ownership needs. Explain what starts the work, what restarts it and what cleans it up.

Network calls should not accidentally repeat because a key is unstable. Durable user intent should not disappear merely because composition ended.

A key has to be the input whose change should restart the work. A stable key can hide a changed account or query, and an unstable one restarts work for nothing.

A saved query with an explicit submit

A search form restores its text and sends the same request again. The saved value can be right while the side-effect policy is wrong. This form keeps a small query in saved UI state and calls a callback only when the person presses Search.

Kotlin
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.material3.Button
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.dp

@Composable
fun QueryForm(onSubmit: (String) -> Unit) {
    var query by rememberSaveable { mutableStateOf("") }
    Column(Modifier.safeDrawingPadding().padding(16.dp)) {
        OutlinedTextField(
            value = query,
            onValueChange = { query = it },
            label = { Text("Search query") },
            modifier = Modifier.testTag("query")
        )
        Button(
            onClick = { onSubmit(query.trim()) },
            enabled = query.isNotBlank(),
            modifier = Modifier.testTag("submit")
        ) { Text("Search") }
    }
}

The query belongs to this form. Blank input disables the button, the callback receives trimmed text, and restoring the query never invokes it. The containing app decides what a submission means. If the product wants a search on every change, define cancellation, debounce and stale-result policy first, then pick the effect owner.

A test like this checks three things in a Compose instrumentation test: blank and whitespace input keep submit disabled, editing does not submit while pressing the button submits trimmed text, and StateRestorationTester restores the query without calling submit. That emulates saved-state recreation inside the Compose harness. It is not a process-kill experiment, and it does not cover durable search or reordered lists.

Expect the follow-up: the form now appears in a list of saved searches and an item moves. Which form keeps which query? That depends on keys that follow item identity, not index. I would test it by moving items that hold different text and checking where each value lands.

Performance without folklore

Measure recomposition, layout and rendering before adding annotations. Keep models stable where it naturally improves reasoning, but do not trade correctness for theoretical skipping.

Discuss baseline profiles, image work, lazy lists and tracing as parts of a complete performance answer.