代码之家  ›  专栏  ›  技术社区  ›  eggie

Jetpack Compose在没有相关项目的LaunchedEffect的情况下不更新

  •  0
  • eggie  · 技术社区  · 1 年前

    有人能告诉我Jetpack Compose和ViewModel的问题吗。

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

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

    在ViewModel中,我有:

    1. 私人本地产品列表,
    2. 布尔按钮状态和
    3. 作为可突变状态<列表<ProductEntity>>。这设置为从本地产品列表中的值开始
    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来触发其余的过程。

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

    谢谢

    1 回复  |  直到 1 年前
        1
  •  0
  •   Owais Yosuf    1 年前

    考虑将产品作为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())