Reputation: 2325
The following content is from the article.
1: I don't understand fully if I can use State<ArrayList<T>>
or State<mutableListOf()>
for observed by Compose to trigger recomposition when they change?
2: I'm very strange why State<List<T>>
and the immutable listOf()
can be observed by Compose to trigger recomposition when they change but in fact List<T>
and immutable listOf()
are immutable, could you give me some sample codes?
Caution: Using mutable objects such as ArrayList or mutableListOf() as state in Compose will cause your users to see incorrect or stale data in your app.
Mutable objects that are not observable, such as ArrayList or a mutable data class, cannot be observed by Compose to trigger recomposition when they change.
Instead of using non-observable mutable objects, we recommend you use an observable data holder such as State<List> and the immutable listOf().
Upvotes: 4
Views: 5617
Reputation: 6369
I managed to do like this:
@Composable
fun ComposeListExample(
allObjects: List<Object>,
selectedObjects: List<Object>
) {
val selectedItems = remember {
mutableStateListOf<Object>().apply { addAll(selectedObjects) }
}
Column {
allObjects.forEach { item ->
SomeView(
title = item.title,
onSelect = {
if (selectedItems.contains(item)) {
selectedItems.remove(item)
} else {
selectedItems.add(item)
}
})
}
}
}
Upvotes: 1
Reputation: 14887
The core concept is
Recomposition happens only when an observable state change happens.
For mutable objects, we have options to use add()
, remove()
and other methods and modify the object directly.
But the change would not trigger a recomposition as the change is not observable. (The object instance is NOT changed)
Even for mutable objects, we can trigger proper recomposition by assigning them to a new object instance. (The object instance is changed)
Hence using mutable objects is error-prone.
We can also, see a lint error due to this problem.
On the other hand, an immutable object like list
can not be modified. They are replaced with a new object instance.
Hence they are observable and proper recomposition happens. (The object instance is changed)
Use this as an example to understand the concept.
@Composable
fun ComposeListExample() {
var mutableList: MutableState<MutableList<String>> = remember {
mutableStateOf(mutableListOf())
}
var mutableList1: MutableState<MutableList<String>> = remember {
mutableStateOf(mutableListOf())
}
var arrayList: MutableState<ArrayList<String>> = remember {
mutableStateOf(ArrayList())
}
var arrayList1: MutableState<ArrayList<String>> = remember {
mutableStateOf(ArrayList())
}
var list: MutableState<List<String>> = remember {
mutableStateOf(listOf())
}
Column(
Modifier.verticalScroll(state = rememberScrollState())
) {
// Uncomment the below 5 methods one by one to understand how they work.
// Don't uncomment multiple methods and check.
// ShowListItems("MutableList", mutableList.value)
// ShowListItems("Working MutableList", mutableList1.value)
// ShowListItems("ArrayList", arrayList.value)
// ShowListItems("Working ArrayList", arrayList1.value)
// ShowListItems("List", list.value)
Button(
onClick = {
mutableList.value.add("")
arrayList.value.add("")
val newMutableList1 = mutableListOf<String>()
mutableList1.value.forEach {
newMutableList1.add(it)
}
newMutableList1.add("")
mutableList1.value = newMutableList1
val newArrayList1 = arrayListOf<String>()
arrayList1.value.forEach {
newArrayList1.add(it)
}
newArrayList1.add("")
arrayList1.value = newArrayList1
val newList = mutableListOf<String>()
list.value.forEach {
newList.add(it)
}
newList.add("")
list.value = newList
},
) {
Text(text = "Add")
}
}
}
@Composable
private fun ShowListItems(title: String, list: List<String>) {
Text(title)
Column {
repeat(list.size) {
Text("$title Item Added")
}
}
}
P.S: Use mutableStateListOf
if you have a list of items that needs to be modified as well as trigger recomposition properly.
Upvotes: 8