18

I'm new to Jetpack Compose and I've spent some hours to find how to make a LazyColumn update what I update my list. I've read that it needs to be a immutable list to update LazyColumn, but I can't seem to get it to work.

The code looks like:

@Composable
fun CreateList() {
    var myList : List<DailyItem> by remember { mutableStateOf(listOf())}
    
    myList = getDailyItemList() // Returns a List<DailyItem> with latest values and uses mutable list internally
    
    // Function to refresh the list
    val onUpdateClick = {
        // Do something that updates the list
        ...
        // Get the updated list to trigger a recompose
        myList = getDailyItemList()
    }
    // Create the lazy column
    ...
}

I have tried several things and either is the list never updated when tapping the update button or only the first item is updated but not the rest of the items in the list. I looked in the documentation and there it says this, but I don't understand it:

Instead of using non-observable mutable objects, we recommend you use an observable data holder such as State<List> and the immutable listOf().

How to update the list so the LazyColumn is updated?

Mackan
  • 1,305
  • 2
  • 17
  • 30

2 Answers2

25

Use SnapshotStateList, the list is mutable. Any modification (add, remove, clear, ...) to the list will trigger an update in LazyColumn.

Similar to mutableListOf() (for MutableList) there is mutableStateListOf() to create a SnapshotStateList.

Extention function swapList() just combines clear() and addAll() calls to replace old list with new list.

fun <T> SnapshotStateList<T>.swapList(newList: List<T>){
    clear()
    addAll(newList)
}

@Composable
fun CreateList() {
    val myList = remember { mutableStateListOf<DailyItem>() }
    
    myList.swapList(getDailyItemList()) // Returns a List<DailyItem> with latest values and uses mutable list internally

    // Function to refresh the list
    val onUpdateClick = {
        // Do something that updates the list
        ...
        // Get the updated list to trigger a recompose
        myList.swapList(getDailyItemList())
    }
    // Create the lazy column
    ...
}
Om Kumar
  • 1,404
  • 13
  • 19
  • 1
    I tried doing this but it didnt work for me. my code is here : https://pastebin.com/RfsRf8bf – mrtechmaker Oct 26 '21 at 17:04
  • 1
    @KaranAhuja You are updating content of an item, not the item itself. MutableStateList won't know if the content within an item changes. Check this one https://stackoverflow.com/questions/69718059/android-jetpack-compose-mutablestatelistof-not-doing-recomposition If you need more then please consider creating a new question for it. – Om Kumar Oct 27 '21 at 07:47
  • @OmKumar Thanks for your comment. It is exactly what i was looking for. I also checked the other question you mentioned. That is exactly my question. Thanks bro. – mrtechmaker Oct 28 '21 at 18:35
2

See the basic idea is to get compose treat the list as state. Now that, you are able to achieve using mutableStateOf(initialValue),

Okay, the process is this,.

We create a variable, initialising it as a mutable state of something

Then we assign that variable to the lazy column. It is not necessary to assign it to the items parameter of the column, but that is our use case here. Otherwise, inside the Composable containing the lazy column, you could just type the name of the variable and even that will work since all we want, is compose to get a message that this variable is being read by the Composable.

Back to the question,

We create a variable, say val mList: List<Int> by remember { mutableStateOf (listOf()) }

Lazycolumn{
items(items = mList){
Text(it)
}
}

Button(onClick = { mList = mList + listOf(mList.size())})

Clicking the button adds a new number to the list, which is reflected in the LazyColumn's UI.

Richard Onslow Roper
  • 5,477
  • 2
  • 11
  • 42