android - 更新列表元素内容时 Jetpack Compose : No recomposition happening,

标签 android kotlin android-jetpack-compose android-viewmodel lazycolumn

我正在尝试使用 Android 的 Jetpack Compose。
对于简单的用例,一切都按预期工作,
但我有一些 缺少重组的问题对于更高级的案例。
这是我在 stackoverflow 上的第一篇文章。我希望我能很好地描述我的问题以获得一些帮助。 ;)
我的模特 :
我正在模拟 存储 成分系统,其中

  • 一个 成分由名称和可选图标组成:
  • data class Ingredient(val name: String, @DrawableRes val iconResource: Int? = null)
    
  • 一个 存储项目 由一种成分和一种原料组成(这种成分的储存量):
  • data class StorageItem(val ingredient: Ingredient, var stock: Int)
    
    我的可组合物 :
    我的 的组合StorageUi 应该列出所有存储项目
    并显示成分以及库存的图标和名称。
    对于这篇文章,我去掉了所有不相关的修饰符和格式以简化可读性。
    (请注意,我用没有 View 模型的第二个版本重载了我的 StorageScreen 组合
    以便于测试并促进 Android Studio 中的预览功能。)
        @Composable
        fun StorageScreen(viewModel: StorageViewModel) {
            StorageScreen(
                navController = navController,
                storageItems = viewModel.storageItems,
                onIngredientPurchased = viewModel::purchaseIngredient
            )
        }
    
        @Composable
        fun StorageScreen(storageItems: List<StorageItem>, onIngredientPurchased: (StorageItem) -> Unit) {
            Column {
                TitleBar(...)
                IngredientsList(storageItems, onIngredientPurchased)
            }
        }
    
        @Composable
        private fun IngredientsList(storageItems: List<StorageItem>, onIngredientPurchased: (StorageItem) -> Unit) {
            LazyColumn {
                items(storageItems) { storageItem ->
                    IngredientCard(storageItem, onIngredientPurchased)
                }
            }
        }
    
        @Composable
        private fun IngredientCard(storageItem: StorageItem, onIngredientPurchased: (StorageItem) -> Unit) {
            Card(
                Modifier.clickable { onIngredientPurchased(storageItem) }
            ) {
                Row {
                    ImageIcon(...)
    
                    Text(storageItem.ingredient.name)
    
                    Text("${storageItem.stock}x")
                }
            }
        }
    
    我的 View 型号:
    在我的 ViewModel 中,我
  • 创建一个可变状态列表(此处未显示数据的初始化)
  • 如果用户点击成分卡,则提供增加库存的事件处理程序
  •     class StorageViewModel : ViewModel() {
    
            var storageItems = mutableStateListOf<StorageItem>()
                private set
    
            fun purchaseIngredient(storageItem: StorageItem) {
                storageItem.stock += 1
            }
    
        }
    
    问题:更改成分的库存时不会发生重组
    我尝试更改事件处理程序以简单地从列表中删除被点击的项目:
            fun purchaseIngredient(storageItem: StorageItem) {
                storageItems.remove(storageItem)
            }
    
    瞧,UI 重新组合,轻拍的成分消失了。
    我学到了什么:
  • mutableStateListOf() 确实观察到列表的变化(添加、删除、重新排序)
  • mutableStateListOf() 不会观察到列表中元素的变化(成分名称/图标/库存变化)

  • 我想向你们学习:
  • 你将如何解决这个问题?
  • 如果列表中的任何元素更改其状态,我该怎么做才能实现重组?
  • 最佳答案

    What can I do to achieve a recomposition, if any element within the list changes its state?


    仅当您更改列表本身时才会发生重组。你可以这样做。
    class StorageViewModel : ViewModel() {
    
         var storageItems by mutableStateOf(emptyList<StorageItem>())
            private set
    
         fun purchaseIngredient(storageItem: StorageItem) {
            storageItems = storageItems.map { item ->
                if(item == storageItem)
                    item.copy(stock = item.stock + 1)
                else
                    item
            }
         }
    }
    
    由于这是一个非常常见的操作,因此您可以创建一个扩展函数以使其看起来更好一些。
    fun <T> List<T>.updateElement(predicate: (T) -> Boolean, transform: (T) -> T): List<T> {
        return map { if (predicate(it)) transform(it) else it }
    }
    
    fun purchaseIngredient(storageItem: StorageItem) {
        storageItems = storageItems.updateElement({it == storageItem}) {
            it.copy(stock = it.stock + 1)
        }
    }
    
    

    关于android - 更新列表元素内容时 Jetpack Compose : No recomposition happening,,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69711167/

    相关文章:

    java - 将类转换为服务

    kotlin - Intellij Idea 插件,创建 Kotlin PSI 访问者

    android - 我们可以在另一个类中使用来自其他类的可组合函数吗?

    android - 如何在 Jetpack Compose 中实现平移 + 缩放动画?

    java - EditText OnClick 异常

    android - 将 Google 示例 Android 项目导入 Android Studio 的正确方法

    android - 方法 openFragmentTransaction() 未定义类型 new ActionBar.OnNavigationListener(){}

    interface - 带有接口(interface)样板的 Kotlin 数据类

    android - 如何在不点击的情况下在谷歌地图可组合标记上显示标题和 fragment ?

    android - 如何在jetpack compose中通过lambda返回columnScope/RowScope