Reputation: 60341
I have a todo list in Jetpack Compose displayed in LazyColumn.
data class TodoItem(val id: Int, val title: String, var urgent: Boolean = false)
val todoList = listOf(
TodoItem(0, "My First Task", true),
TodoItem(1, "My Second Task", true),
TodoItem(2, "My Third Task"),
)
@Composable
fun Greeting(name: String) {
val todoListState = remember {
todoList.toMutableStateList()
}
LazyColumn(modifier = Modifier.fillMaxHeight()) {
items(items = todoListState, itemContent = { item ->
Row(modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
Text(
modifier = Modifier.weight(1f).padding(8.dp),
text = item.title)
Checkbox(
checked = item.urgent,
onCheckedChange = {
val index = todoListState.indexOf(item)
todoListState[index] = todoListState[index].copy(urgent = it)
Log.d("Track", "$todoList")
}
)
}
})
}
}
The first time it is
[TodoItem(id=0, title=My First Task, urgent=true),
TodoItem(id=1, title=My Second Task, urgent=true),
TodoItem(id=2, title=My Third Task, urgent=false)]
After I updated first to false, then it's false
[TodoItem(id=0, title=My First Task, urgent=false),
TodoItem(id=1, title=My Second Task, urgent=true),
TodoItem(id=2, title=My Third Task, urgent=false)]
When I update first to true back, the todoItem
no longer change and remain as
After I updated first to false, then it's false
[TodoItem(id=0, title=My First Task, urgent=false),
TodoItem(id=1, title=My Second Task, urgent=true),
TodoItem(id=2, title=My Third Task, urgent=false)]
I check the todoListState
(the SnapshotStateList), and it's no longer in sync with todoList
. What causes that? How to fix it?
Updated
To fix it, I can use
Checkbox(
checked = item.urgent,
onCheckedChange = {
val index = todoListState.indexOf(item)
todoListState[index] = todoListState[index].copy(urgent = it)
todoList[index].urgent = it
Log.d("Track", "$todoList")
}
)
But that means I have to change 2 item at the same time. How can I just change one, and get both updated?
Upvotes: 1
Views: 7609
Reputation: 67443
The reason it's not updated because toMutableStateList adds items of list
fun <T> Collection<T>.toMutableStateList() = SnapshotStateList<T>().also { it.addAll(this) }
You should create one SnapshotStateList and add, remove and update items on this list. The approach you use is not correct.
If you wish to create a SnapshotStateList with initial items you can use
I missed SnapShotStateList doesn't have an add function.
SnapShotState can be used with addAll or you need to add them as items without
val todoList = remember {
mutableStateListOf().apply {
add(TodoItem(id=0, title="My First Task", urgent=true))
add(TodoItem(id=1, title="My Second Task", urgent=true))
...
}
}
Should instead be as in @Elye's answer or as
val todoList = mutableStateListOf().apply {
addAll(initialList)
}
or if list is a parameter of a function or need to retrieve items from a list is required use addAll or toMutableStateList but use only SnapshotStateList for updating items.
Jetpack Compose lazy column all items recomposes when a single item update
Upvotes: 6
Reputation: 60341
I use
val todoList = mutableStateListOf(
TodoItem(0, "My First Task", true),
TodoItem(1, "My Second Task", true),
TodoItem(2, "My Third Task"),
)
UPDATED
I learn this answer, by evolving what was proposed by @Thracian in https://stackoverflow.com/a/74968199/3286489.
The answer provided by @Thracian is not compilable as shonw in the
So I made the above answer from it and put it here as a reference to a compilable answer.
Upvotes: 1