mutableStateListOf and mutableStateMapOf in Jetpack Compose
mutableStateListOf and mutableStateMapOf in Jetpack Compose
Jetpack Compose provides mutableStateListOf and mutableStateMapOf as observable collection types that integrate with the snapshot state system. Unlike regular MutableList or MutableMap, modifications to these collections are tracked by Compose and automatically trigger recomposition for any composable that reads them. Understanding how these collections work under the hood and when to use them over alternatives like mutableStateOf(list) is a common topic in Compose interviews. By the end of this lesson, you will be able to:
- Explain how
mutableStateListOfandmutableStateMapOfintegrate with the snapshot system. - Distinguish between
mutableStateListOfandmutableStateOf(mutableListOf())in terms of granularity. - Apply observable collections correctly with
rememberto build reactive UIs. - Identify common mistakes that break observation or cause unexpected recompositions.
How Observable Collections Work
mutableStateListOf returns a SnapshotStateList, which implements MutableList and participates in Compose's snapshot system. Every structural mutation (add, remove, set, clear) writes to the snapshot, and every read (get, iterate, size) creates a dependency. Compose tracks these reads and invalidates the composition when a mutation occurs:
@Composable
fun TaskList() {
val tasks = remember { mutableStateListOf("Setup", "Build", "Deploy") }
Column {
tasks.forEach { task ->
Text(text = task)
}
Button(onClick = { tasks.add("Test") }) {
Text("Add Task")
}
}
}
When the button is clicked, tasks.add("Test") mutates the SnapshotStateList. Compose detects that the forEach loop reads from this list and schedules recomposition for TaskList. The new item appears without any manual notification.
mutableStateMapOf works identically but for key value pairs, returning a SnapshotStateMap that implements MutableMap:
@Composable
fun PreferencesScreen() {
val prefs = remember {
mutableStateMapOf("notifications" to true, "darkMode" to false)
}
Column {
prefs.forEach { (key, value) ->
Row {
Text(text = key)
Switch(
checked = value,
onCheckedChange = { prefs[key] = it }
)
}
}
}
}
This interview continues for subscribers
Subscribe to Dove Letter for full access to exclusive interviews about Android and Kotlin development.
Become a Sponsor