与 Livedata 不同,使用 Flow in Room 查询在更新 table 条目时不会触发刷新,但在我删除或插入条目时有效
Unlike Livedata, using Flow in Room query doesn't trigger a refresh when updating a table entry but works if I delete or insert an entry
当使用 Livedata 作为 return 类型进行 select* 查询时 table 在房间里,然后我观察它,如果我 update/insert/delete 中的一个条目 table。然而,当我尝试使用 Kotlin Flow 时,我只得到 2 个触发器。
第一个触发器给出空值,因为状态流的初始值为空。第二个触发器是房间 table.
中的条目列表
如果我对数据库执行 insert/delete 操作,我会收到来自 StateFlow 的触发器。
但是,如果我更新条目,Stateflow 不会触发。
N.B: 更新操作在数据库上正常工作。我使用数据库检查器进行了检查。
数据class & DAO
@Entity
data class CartItem (
@PrimaryKey
val itemId: Int,
var itemQuantity: Int=1
)
@Dao
interface CartDao {
@Query("SELECT * FROM CartItem")
fun getAllItems(): Flow<List<CartItem>>
@Update
suspend fun changeQuantityInCart(cartItem:CartItem)
@Insert
suspend fun insert(item: CartItem)
@Delete
suspend fun delete(cartItem:CartItem)
}
ViewModel
val cartItems: StateFlow<List<CartItem>?> =
repo.fetchCartItems().stateIn(viewModelScope, SharingStarted.Lazily, null)
片段
viewLifecycleOwner.lifecycleScope.launchWhenStarted {
viewModel.cartItems.collect {
Log.e("Update","Update")
}
我的陷阱是我是这样更新对象的:
currentItem.itemQuantity = currentItem.itemQuantity + 1
changeQuantity(currentItem)
(currentItem
是 class CartItem
的一个对象,它最初是从 DAO 中的 getAllItems
流接收的。)
(changeQuantity
fun 在 DAO 中调用 changeQuantityInCart
fun。
这导致 StateFlow 中 CartItem 对象的引用在调用 DB 更新之前使用新的 itemQuantity 值保存对象的更新值。
之后在DAO中调用Update fun时,DB entry被更新,Flow值发生变化,但是放到Stateflow中却没有检测到变化。因此,stateflow 不会触发,因为它是 stateflow 与 livedata 的不同之处。
如果是livedata,无论新值是否相同都会触发
因此,为了解决这个错误,在调用数据库更新操作之前不要更改 stateFlow 中对象的值,如下所示:
val updatedCartItem = cartItem.copy(itemQuantity = cartItem.itemQuantity + 1)
changeQuantity(updatedCartItem)
当使用 Livedata 作为 return 类型进行 select* 查询时 table 在房间里,然后我观察它,如果我 update/insert/delete 中的一个条目 table。然而,当我尝试使用 Kotlin Flow 时,我只得到 2 个触发器。
第一个触发器给出空值,因为状态流的初始值为空。第二个触发器是房间 table.
中的条目列表如果我对数据库执行 insert/delete 操作,我会收到来自 StateFlow 的触发器。 但是,如果我更新条目,Stateflow 不会触发。
N.B: 更新操作在数据库上正常工作。我使用数据库检查器进行了检查。
数据class & DAO
@Entity
data class CartItem (
@PrimaryKey
val itemId: Int,
var itemQuantity: Int=1
)
@Dao
interface CartDao {
@Query("SELECT * FROM CartItem")
fun getAllItems(): Flow<List<CartItem>>
@Update
suspend fun changeQuantityInCart(cartItem:CartItem)
@Insert
suspend fun insert(item: CartItem)
@Delete
suspend fun delete(cartItem:CartItem)
}
ViewModel
val cartItems: StateFlow<List<CartItem>?> =
repo.fetchCartItems().stateIn(viewModelScope, SharingStarted.Lazily, null)
片段
viewLifecycleOwner.lifecycleScope.launchWhenStarted {
viewModel.cartItems.collect {
Log.e("Update","Update")
}
我的陷阱是我是这样更新对象的:
currentItem.itemQuantity = currentItem.itemQuantity + 1
changeQuantity(currentItem)
(currentItem
是 class CartItem
的一个对象,它最初是从 DAO 中的 getAllItems
流接收的。)
(changeQuantity
fun 在 DAO 中调用 changeQuantityInCart
fun。
这导致 StateFlow 中 CartItem 对象的引用在调用 DB 更新之前使用新的 itemQuantity 值保存对象的更新值。
之后在DAO中调用Update fun时,DB entry被更新,Flow值发生变化,但是放到Stateflow中却没有检测到变化。因此,stateflow 不会触发,因为它是 stateflow 与 livedata 的不同之处。
如果是livedata,无论新值是否相同都会触发
因此,为了解决这个错误,在调用数据库更新操作之前不要更改 stateFlow 中对象的值,如下所示:
val updatedCartItem = cartItem.copy(itemQuantity = cartItem.itemQuantity + 1)
changeQuantity(updatedCartItem)