请有人能解答我在 Jetpack Compose 和 ViewModel 方面遇到的问题吗?
我有一个名为 ProductEntity 的数据类。
data class ProductEntity(
var id: Int = 0,
var name: String = "",
var quant: Int = 1,
)
在 ViewModel 中我有:
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)
}
}
我有主屏幕可组合项
在那里我有:
我有一个按钮,它显示过滤列表中的第一项,并在按下时执行三件事
最后我有一个由按钮状态触发的 LaunchedEffect,它什么也不做。
@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)
}
}
}
}
在删除 LaunchedEffect 或按钮状态未更改之前,这一切都可以正常工作。此时没有任何作用 - 按钮文本不会更新,过滤列表也不会更改。
我看不出这是如何发生的以及为什么我需要按钮状态 LaunchedEffect 来触发该过程的其余部分。
如果您能提供任何帮助,我们将不胜感激。
谢谢
考虑将产品设为 ViewModel 本身的 MutableState 变量。这样,Compose 就可以直接观察到这个状态的变化,并相应地触发重组。
class TestGlobalViewModel : ViewModel() {
// ...
var products by mutableStateOf(localList)
private set
fun updateProducts(counter: Int) {
// ... (no need to create a new mutableStateOf)
products = localList2
}
}
如果您将 Jetpack Compose 与 ViewModel 结合使用,建议在 ViewModel 中使用 LiveData 并在 Compose 中观察它。这样,Compose 就可以自动处理观察和重组。
class TestGlobalViewModel : ViewModel() {
private val _products = MutableLiveData<List<ProductEntity>>(localList)
val products: LiveData<List<ProductEntity>> get() = _products
fun updateProducts(counter: Int) {
// ...
_products.value = localList2
}
}
在您的可组合项中:
val products by vm.products.observeAsState(emptyList())