在包含对象内部进行更改时,Jetpack Compose LazyColum 状态不会更改

Jetpack Compose LazyColum state not changing when changes are made inside of containing objects

下面是一个简单的购物车实现,如果单击列表项,qty 的值应该增加 1...

但是 ViewModel 中的值不知何故发生了变化,但未反映在 UI 中(未使用新的数量值进行重组)

我认为问题出在这部分: LazyColumn {items(cartInfo.value!!.cartItems){...}

因为 cartItems 不是直接的状态值,这就是为什么不触发 LazyColumn UI.

的重组的原因

但无法解决此问题,因为 mutableStateOf<CartInfo?> 已修复,我不想要 MutableList<CartItem>

的单独状态
data class User(var id: String, var name: String)
data class Product(var id: String, var name: String)
data class CartItem(var product: Product, var qty: Int)
data class CartInfo(val userid: String, val cartItems: MutableList<CartItem>)

val user = User("1", "A")
val item1 = CartItem(Product("1", "iPhone"), 1)
val item2 = CartItem(Product("2", "Xbox"), 1)
val cart = CartInfo(user.id, mutableListOf(item1, item2))

class MainViewModel : ViewModel() {
    private val _cartInfo = mutableStateOf<CartInfo?>(null)
    val cartInfo: State<CartInfo?> = _cartInfo

    init {
        _cartInfo.value = cart
    }

    fun increaseQty(product: Product, user: User) {
        viewModelScope.launch {
            var cartInfo = cartInfo.value

            if (user.id == cartInfo?.userid) {
                var cartItems = cartInfo.cartItems.map {
                    if (it.product.id == product.id) {
                        it.qty += 1
                        it
                    } else
                        it
                }
                _cartInfo.value = cartInfo.copy(cartItems = cartItems as MutableList<CartItem>)
            }
//            Log.d("debug", "viewmodel: ${cartInfo?.cartItems.toString()}")
        }
    }

}


class MainActivity : ComponentActivity() {
    private val viewModel by viewModels<MainViewModel>()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyApplicationTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    val cartInfo = viewModel.cartInfo
                    Log.d("debug", cartInfo.toString())

                    LazyColumn {
                        items(cartInfo.value!!.cartItems) {
                            Card(modifier = Modifier
                                .fillMaxWidth()
                                .padding(5.dp)
                                .clickable {
                                    viewModel.increaseQty(it.product, user)
                                }) {
                                Row() {
                                    Text(
                                        text = "${it.product.name}",
                                        modifier = Modifier.weight(1f).padding(10.dp)
                                    )
                                    Text(
                                        text = "qty: ${it.qty}"
                                    )
                                }

                            }

                        }
                    }
                }
            }
        }
    }
}

提前致谢

使用derivedStateOf观察对象属性的变化,请尝试:

val cartInfo by remember{ derivedStateOf{viewModel.cartInfo!!.cartItems}}

items(cartInfo)

或选中此 answer 并修改您的数据 class 使用复制更改

在这一行 _cartInfo.value = cartInfo 中,您在 _cartInfo 中设置了相同的对象。

可变状态无法检查您的内部对象的状态是否已更改,它只能检查是否是同一对象。

您可以将您的 CartInfo 设为数据 class,这样您就可以使用 copy 轻松创建新对象。确保您不使用任何 var 或可修改的集合,例如 MutableList 以减少出错的机会。查看 Why is immutability important in functional programming?

data class CartInfo(val id: String, val cartItems: List<Item>)

// usage
_cartInfo.value = cartInfo.copy(cartItems = cartItems)

CartItem(it.product, qty = it.qty + 1) 创建新的 CartItem 解决了问题:

fun increaseQty(product: Product, user: User) {
        viewModelScope.launch {
            var cartInfo = cartInfo.value

            if (user.id == cartInfo?.userid) {
                var cartItems = cartInfo.cartItems.map {
                    if (it.product.id == product.id) {
//                        old:
//                        it.qty += 1
//                        it
//                       changes made:
                        CartItem(it.product, qty = it.qty + 1)
                    } else
                        it
                }
                _cartInfo.value = cartInfo.copy(cartItems = cartItems as MutableList<CartItem>)
            }
        }
}