在包含对象内部进行更改时,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>)
}
}
}
下面是一个简单的购物车实现,如果单击列表项,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>)
}
}
}