I am calling an increaseCount(id: String) method from a composable to increase the value of a parameter in a LiveData List of objects. The value gets updated quite alright but the UI only shows the update once I navigate out. PS: I am using a BottomNavigation view for navigating.
The Composable screen in question looks something like this
@Composabale
fun MyScreen(navController: NavHostController, viewModel: MyViewModel){
val itemList = viewModel.itemList.observeAsState().value
LazyColumn(modifier = Modifier.fillMaxWidth()) {
items(itemList) { item: Item? ->
ItemView(item, viewModel)
}
}
}
@Composable
private fun ItemView(item: Item?, viewModel: MyViewModel) {
Row(
modifier = Modifier.padding(4.dp, 0.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.End
) {
//Counter section
IconButton(onClick = { viewModel.decreaseItemCount(cartItem.itemId) }) {
Icon(
imageVector = Icons.Filled.RemoveCircleOutline,
contentDescription = "Reduce order button",
tint = Color.Gray
)
}
Text(text = "${item.itemQuantity}")
IconButton(onClick = { viewModel.increaseItemCount(item.itemId) }) {
Icon(
imageVector = Icons.Filled.AddCircleOutline,
contentDescription = "Increase order button",
tint = Color(R.color.yellow_700)
)
}
}
The ViewModel side of things looks something like this:
private val _itemList = MutableLiveData<ArrayList<Item>>()
val itemList: LiveData<List<Item>>
get() = _itemList
fun increaseItemCount(id: String) {
val theList = _itemList.value
theList?.find { item ->
item.itemId == id
}?.let { item ->
item.itemQuantity = 1
_itemList.value = theList!!
}
}
The decreaseItemCount function is similar to the increaseItemCount with the only difference being the count is decreasing.
CodePudding user response:
When you update an object property, LiveData
cannot know that this object has changed. And a list still contains the same list of objects.
The solution is to actually create a new object with updated properties. data class is very comfy for this: declare your properties as val
and update them using copy
.
Check out Why is immutability important in functional programming?.
Live data version:
data class Item(val itemId: String, val itemQuantity: Int)
private val _itemList = MutableLiveData<List<Item>>()
val itemList: LiveData<List<Item>>
get() = _itemList
fun increaseItemCount(id: String) {
val theList = _itemList.value?.toMutableList() ?: return
val index = theList.indexOfFirst { it.itemId == id }
if (index == -1) return
theList[index] = theList[index].let {
it.copy(itemQuantity = it.itemQuantity 1)
}
_itemList.value = theList
}
mutableStateListOf
version is a little bit shorted and cleaner:
data class Item(val itemId: String, val itemQuantity: Int)
private val _itemList = mutableStateListOf<Item>()
val itemList: List<Item> = _itemList
fun increaseItemCount(id: String) {
val index = _itemList.indexOfFirst { it.itemId == id }
if (index == -1) return
_itemList[index] = _itemList[index].let {
it.copy(itemQuantity = it.itemQuantity 1)
}
}