LazyColumn Item Keys and State Preservation
LazyColumn Item Keys and State Preservation
When items in a LazyColumn change order, get added, or get removed, Jetpack Compose needs a way to keep each item's remembered state correctly associated with it. Item keys provide this association. Without them, Compose defaults to using the item's position as the key, which causes state to become misapplied when positions change. For rememberSaveable to survive Activity recreation, the key must also be compatible with Android's Bundle mechanism. By the end of this lesson, you will be able to:
- Explain why position based keying causes state misassociation during reordering.
- Describe how stable, unique keys allow Compose to track items across position changes.
- Identify the
Bundlecompatibility requirement for keys used withrememberSaveable. - List the types supported by
Bundlefor key values. - Apply item keys correctly in a
LazyColumnwithrememberSaveablestate.
Position-Based Keying and Its Problems
By default, Compose keys the state of each item in a LazyColumn against its position in the list. If you have a list of five items and each holds a remember { mutableStateOf(0) } counter, the counter at position 0 stays at position 0 regardless of which data item occupies that slot.
When the list reorders, the data item that was at position 0 moves to position 3, but the counter at position 0 stays behind. The user sees the counter value attached to the wrong item. The same problem occurs when items are inserted or removed: state shifts to adjacent positions rather than following the data.
This is particularly visible with interactive items. A text field with user input, a checkbox with a checked state, or an expandable section that is currently open will all display their state on the wrong item after a reorder. The visual result is confusing to the user and difficult to debug because the composable functions are executing correctly. The problem is in how Compose maps state to items.
Stable and Unique Keys
Providing a key through the items DSL solves this problem. The key must be stable (it does not change for a given data item) and unique (no two items share the same key).
data class MyItem(val id: String, val content: String)
@Composable
fun MyStatefulList(myItems: List<MyItem>) {
LazyColumn {
items(
items = myItems,
key = { item -> item.id }
) { dataItem ->
ItemWithState(item = dataItem)
}
}
}
When the list reorders, Compose matches each key to its previous state. The counter that belonged to item "abc" follows item "abc" to its new position. State is associated with identity, not position.
This interview continues for subscribers
Subscribe to Dove Letter for full access to exclusive interviews about Android and Kotlin development.
Become a Sponsor