Home > OS >  Handling state using list in android Jetpack compose
Handling state using list in android Jetpack compose

Time:07-26

I am trying to update a list which is kept as state of a composable view, but the composable view is not recomposed even though the values of list are changed.

var list = remember {mutableStateOf(getListOfItems())}
ItemListView({ selectedItem ->
       list.value =  updateList(selectedItem, list.value)
            }, list.value)

private fun updateList(selectedItem: String,
         itemsList: List<Product>): List<Product> {
    for (item in itemsList){
        // selected item in the view is updated
        item.selected = item.name == selectedItem
    }
    return itemsList
}

Any idea why the composable is not getting updated? I noticed the issue happens when using a List as state.

CodePudding user response:

You need to update value of MutableState, which is a List in your example, to trigger recomposition not any property of value you set to MutableState.

@Stable
interface MutableState<T> : State<T> {
    override var value: T
    operator fun component1(): T
    operator fun component2(): (T) -> Unit
}

But there is another function called mutableStateListOf() which can trigger recomposition when you add or remove items, or update existing one with new instance.

val list =remember {
    mutableStateListOf< Product>().apply {
        addAll(getListOfItems())
    }
}

CodePudding user response:

The jetpack compose looks at your object itself to see if it has changed to decide whether to update it or not. You need to update the list itself to do that:

data class A(var v: Int)

@Composable
fun Test1() {
    var list by remember { mutableStateOf(listOf(A(1), A(2), A(3))) }
    LazyColumn(modifier = Modifier.fillMaxSize()) {
        items(list) {
            Text(text = it.toString())
        }

        item {
            // it does not work
            Button(onClick = {
                list[0].v = 2
            }) { Text("Change value") }

            // it works
            Button(onClick = {
                list = list.map { it.copy(v = it.v   1) }
            }) { Text("Change list") }
        }
    }
}

Also, you can use mutableStateListOf, which will monitor the addition and removal of elements.

@Composable
fun Test2() {
    val list = remember { mutableStateListOf(A(1), A(2), A(3)) }
    LazyColumn(modifier = Modifier.fillMaxSize()) {
        items(list) {
            Text(text = it.toString())
        }

        item {
            // it not work
            Button(onClick = {
                list[0].v = 2
            }) { Text("Change value") }

            // it work
            Button(onClick = {
                list.add(A(3))
            }) { Text("Change list") }
        }
    }
}

In your case, you can represent the selection like this:

val selectedList = remember { mutableStateListOf<String>() }
LazyColumn(modifier = Modifier.fillMaxSize()) {
    items(list) {
        val selected = selectedList.contains(it.name)
        Text(text = if (selected) "selected" else "not selected")
        Button(onClick = {
            if (!selected) selectedList.add(it.name)
        }) { Text("Select it") }
    }
}
  • Related