Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Compose lazycolumn does not update when livedata is changed

I have a list of items where each has a checkbox. The state of the checkbox needs to be stored in the viewmodel and preferable the list in the viewmodel should be the only source of truth.

@Composable
fun Screen(viewModel: ViewModel) {
    val list by viewModel.items.observeAsState()

    LazyColumn {
        list?.let { items ->
            items(items) { item -> 
                ListItem(
                    text = {
                        Text(item.name)
                    },
                    secondaryText = {
                        Text(item.phoneNumber)
                    },
                    icon = {
                        Checkbox(
                            modifier = Modifier.padding(8.dp),
                            checked = item.selected,
                            onCheckedChange = {
                                //TODO

                            }
                        )
                    }
                )
            }
        }
    }
}

I have tried to update the item.selected by updating the list (MutableLiveData<List<Object>> in viewmodel) in the onCheckedChange callback, but the UI does not update. If i scroll down and then up the UI updates and the checkbox appears to be checked. Why does it not update?

like image 826
OscarCreator Avatar asked Feb 28 '26 07:02

OscarCreator


2 Answers

MutableLiveData knows nothing about the object it holds. It cannot send you new value when some inner object property is updated.

To solve this with live data, you need to set new value to you items, setting the same value will be enough:

fun setSelected(index: Int, selected: Boolean) {
    items.value!![index].selected = selected
    items.value = items.value
}

But if you're not bind to LiveData by other dependencies, I suggest you not using it. Using mutableStateListOf with immutable data class is much cleaner:

data class Object(val selected: Boolean)

class VM: ViewModel() {
    val items = mutableStateListOf<Object>()

    fun setSelected(index: Int, selected: Boolean) {
        items[index] = items[index].copy(selected = selected)
    }
}

In both cases, you need the object index, you can get it with itemsIndexed:

val list = viewModel.items
LazyColumn {
    itemsIndexed(list) { index, item -> 
        // ...
        onCheckedChange = {
            viewModel.setSelected(index, it)
        }
    // ...
    }
}
like image 59
Philip Dukhov Avatar answered Mar 07 '26 07:03

Philip Dukhov


In my Case

I were using a mutable list like

MutableLiveData<MutableList<Car>>()

I changed it to a list like this and it worked. :(

MutableLiveData<List<Car>>()
like image 32
Abdullqadir Avatar answered Mar 07 '26 06:03

Abdullqadir