Please can someone throw any light on the problem that I have with Jetpack Compose and a ViewModel.
I have a data class called ProductEntity.
data class ProductEntity(
var id: Int = 0,
var name: String = "",
var quant: Int = 1,
)
In a ViewModel I have:
- private local list of products,
- Boolean button state and
- a Products list which is a MutableState<List<ProductEntity>>. This is set to start with the values from the local list of products
- a function to update the product list based on a counter number passed
class TestGlobalViewModel : ViewModel() {
private val localList = ArrayList<ProductEntity>().apply {
add(ProductEntity(name = "a"))
add(ProductEntity(name = "b"))
add(ProductEntity(name = "c"))
}
var buttonState by mutableStateOf(false)
var products = mutableStateOf<List<ProductEntity>>(
localList
)
fun updateProducts(counter:Int){
val localList2 = ArrayList<ProductEntity>()
localList2.add(ProductEntity(name = "a$counter"))
localList2.add(ProductEntity(name = "b$counter"))
localList2.add(ProductEntity(name = "c$counter"))
localList2.add(ProductEntity(name = "a${counter + 1}"))
localList2.add(ProductEntity(name = "b${counter + 1}"))
localList2.add(ProductEntity(name = "c${counter + 1}"))
localList2.add(ProductEntity(name = "a${counter + 3}"))
localList2.add(ProductEntity(name = "b${counter + 3}"))
localList2.add(ProductEntity(name = "c${counter + 3}"))
products = mutableStateOf(localList2)
}
}
I have the HomeScreen Composable
In there I have:
- a reference to the ViewModel
- mutable state of a counter
- mutable state of a filtered list. This latter list is updated whenever the Products list is replaced.
I have a Button that displays the first item in the filtered list and does three things when pressed
- Increments the counter
- updates the product list
- toggles the buttonState variable in the view model
Finally I have a LaunchedEffect triggered by the button state that does nothing.
@Composable
fun HomeScreen() {
val vm = viewModel<TestGlobalViewModel>()
var counter by remember {
mutableStateOf(1)
}
var filteredList by remember {
mutableStateOf<List<ProductEntity>>(emptyList())
}
filteredList = run {
val filtered = ArrayList<ProductEntity>()
vm.products.value.forEach {
if (it.name.contains("a")) filtered.add(it)
}
filtered
}
LaunchedEffect(vm.buttonState) {}
TestTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Button(onClick = { // temporary print
counter += 1
vm.updateProducts(counter)
Log.i("CEtest", // print out the filtered list
buildString {
filteredList.forEach {
append("filteredList = $it \n")
}
})
vm.buttonState = vm.buttonState == false
}) {
Text(text = filteredList[0].name)
}
}
}
}
This works perfectly until either the LaunchedEffect is removed or the button state is not changed. At that point nothing works - the button text is not updated and the filtered list is not changed.
I cannot see how this is occurring and why I need the button state LaunchedEffect to trigger the rest of the process.
Any help you can give would be gratefully appreciated.
Thanks