There is a viewmodel VM. There is one variable v of type MutableStateFlow<List>.
var attendanceStates = MutableStateFlow<List<AttendanceState>>(arrayListOf())
private set
Model : AttendanceState
data class AttendanceState (
var memberId: Int,
var memberName: String = "",
var isPresent: Boolean = false,
var leaveApplied: Boolean = false
)
The variable is mapped to a LazyColumn
The Lazy column contains Checkboxes. If i update the checkbox, the event is propagated to VM and from there I'm changing the value of v
attendanceStates.value[event.index].copy(leaveApplied = event.hasApplied)
attendanceStates.value = attendanceStates.value.toList()
But this is not updating the LazyColumn.
In the Composable Function,
val attendances by viewModel.attendanceStates.collectAsState()
LazyColumn(modifier = Modifier.fillMaxWidth().padding(top = 24.dp)) {
Log.e("Attendance","Lazy Column Recomposition")
items(attendances.size) { index ->
AttendanceCheckBox(attendanceState = attendances[index], modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), onAttendanceStatusChangeListener = { viewModel.onEvent(AttendanceEvent.IsPresentStatusChanged(index, it)) }, onLeaveAppliedStatusChangeListener = { viewModel.onEvent(AttendanceEvent.IsLeaveAppliedStatusChanged(index, it)) })
}
}
But recomposition is not happening.
CodePudding user response:
Try this:
viewModelScope.launch {
val helper = ArrayList(attendanceStates.value)
helper[event.index] = helper[event.index].copy(leaveApplied = event.hasApplied)
attendanceStates.emit(helper)
}
Changing an item's properties will not trigger a StateFlow
, you have to replace the whole item with the changed item and emit a new list.
CodePudding user response:
I would recommend SnapshotStateList
instead of a standard List
, this will guarantee an update without having to create a new instance of it like what you would do in an ordinary List
, assuming you call AttendanceState
instance copy()
and updating at least one of its properties with a different value.
var attendanceStates = MutableStateFlow<SnapshotStateList>(mutableStateListOf())
private set
I would also recommend changing the way you use your LazyColumn
where items are mapped by their keys
not just by their index
position,
LazyColumn(modifier = Modifier.fillMaxWidth().padding(top = 24.dp)) {
items(attendances, key = {it.memberId}) {
AttendanceCheckBox(...)
}
}
and if you still need the index
position.
LazyColumn(modifier = Modifier.fillMaxWidth().padding(top = 24.dp)) {
itemsIndexed(attendances, key = { index, item ->
item.memberId
}) { item, index ->
AttendanceCheckBox(...)
}
}
You should also use update
when updating your StateFlow
instead of modifying its value
directly to make it concurrently safe.
attendanceStates.update { list ->
val idx = event.idx
list[idx] = list[idx].copy(leaveApplied = event.hasApplied)
list
}