viewmodelandroid-jetpack-compose-lazy-column

ViewModel does not update list of Object after changes. How to fix this?


I have a ViewModel class:

class ItemsModel : ViewModel() {

    private val _tasks = MutableStateFlow<List<TaskItem>>(listOf())

    val tasks = _tasks.asStateFlow()

    fun onTaskDone(index: Int) {
        _tasks.value = _tasks.value.toMutableList().apply {
            get(index).task.done = !get(index).task.done
        }
    }

    fun onTaskRemove(index: Int) {
        val listSize = _tasks.value.size
        _tasks.value = _tasks.value.toMutableList().apply {
            if (index < listSize)
                removeAt(index)
        }
    }


    fun addTask(task: String) {
        _tasks.value = _tasks.value.toMutableList().apply {
            add(TaskItem(this.size + 1, Task(task)))
        }
    }
}

The data class of TaskItem:

@Parcelize
data class TaskItem(var index: Int, var task: Task) : Parcelable

The data class of Task:

@Parcelize
data class Task(var task: String = "", var done: Boolean = false) : Parcelable

In the target composable screen I call that like this:

...
val itemsModel: ItemsModel = viewModel()
val tasks by itemsModel.tasks.collectAsState()
...

Whenever I call this itemsModel.onTaskDone(index) the LazyColumn doesn't get updated until another changes are made to the list, e.g. adding new task item into the list.

So far I understand, that change doesn't take place on LazyColumn since I change a value within the Object Task that is a variable within TaskItem. If I had a String instead of Task the changes could appear immediately, don't they?

Anyway, I need to get changes shown in LazyColumn. How can I solve this?


Solution

  • I foun a solution if someone should be still loocking for.

    I jst defined a new SnapshotStateList variable within screen:

    var tasks = remember { mutableStateListOf<Task>() }
    

    It allows changing data within the list and recompose LazyColumn like this:

    val item = tasks[index]
    tasks[index] = item.copy(done = !tasks[index].done)
    

    For more info please also check this question and answer.

    Please make sure that you also set a key for LazyColumn:

    itemsIndexed(tasks, key = { _, task -> task.hashCode() }) { index, task -> /* Your code */ }