如果没有不相关项目的 LaunchedEffect,Jetpack Compose 不会更新

问题描述 投票:0回答:1

请有人能解答我在 Jetpack Compose 和 ViewModel 方面遇到的问题吗?

我有一个名为 ProductEntity 的数据类。

data class ProductEntity(
    var id: Int = 0,
    var name: String = "",
    var quant: Int = 1,

    )

在 ViewModel 中我有:

  1. 私人本地产品列表,
  2. 布尔按钮状态和
  3. 一个产品列表,它是一个 MutableState>。这设置为从本地产品列表中的值开始
  4. 根据通过的计数器编号更新产品列表的功能
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)
    }

}

我有主屏幕可组合项

在那里我有:

  1. 对 ViewModel 的引用
  2. 计数器的可变状态
  3. 过滤列表的可变状态。每当更换产品列表时,后一个列表都会更新。

我有一个按钮,它显示过滤列表中的第一项,并在按下时执行三件事

  1. 增加计数器
  2. 更新产品列表
  3. 切换视图模型中的buttonState变量

最后我有一个由按钮状态触发的 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 来触发该过程的其余部分。

如果您能提供任何帮助,我们将不胜感激。

谢谢

kotlin android-jetpack-compose viewmodel mutablelist
1个回答
0
投票

考虑将产品设为 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())
© www.soinside.com 2019 - 2024. All rights reserved.