Room 数据库中的事务返回 LiveData
Transaction in Room Database returning LiveData
我想从旧记录中删除一个 table,然后计算其中的记录数。
@Transaction
private fun getOrdersCount(): LiveData<Int>
{
val now = LocalDateTime.now()
val firstOfMonth = now.withDayOfMonth(1)
subop_pruning(firstOfMonth) // query that deletes older orders
return subop_select_count() // query that returns the number of orders
}
不幸的是,这个查询 return 是一个错误
error: Method annotated with @Transaction must not return deferred/async return type androidx.lifecycle.LiveData. Since transactions are thread confined and Room cannot guarantee that all queries in the method implementation are performed on the same thread, only synchronous @Transaction implemented methods are allowed. If a transaction is started and a change of thread is done and waited upon then a database deadlock can occur if the additional thread attempts to perform a query. This restrictions prevents such situation from occurring.
现在,我想在一个事务中按顺序执行 -delete- 和 -select count- 操作序列,return 来自 -select 的 LiveData计数操作。这在我看来是合法的。
问题:
- 事务中的查询不是顺序执行的吗?
- 为什么会出错?
- 如果无法从交易中获取 LiveData,如何获得相同的行为,例如使用
MutableLiveData
和 InvalidationTracker.Observer#onInvalidated
通知?
第 1 点和第 2 点仍未得到解答,无论如何我是如何绕过这个问题的(根据第 3 点)。希望对某人有所帮助:
fun getOrderCount(): LiveData<Int> = object : LiveData<Int>(0) {
val observer = object : InvalidationTracker.Observer("order_table") {
override fun onInvalidated(tables: MutableSet<String>) {
requestOrderCount()
}
}
override fun onActive() {
super.onActive()
val tracker =
MyRoomDatabase.getInstance(applicationContext).invalidationTracker;
tracker.addObserver(observer)
requestOrderCount()
}
override fun onInactive() {
super.onInactive()
val tracker =
MyRoomDatabase.getInstance(applicationContext).invalidationTracker;
tracker.removeObserver(observer)
}
private fun requestOrderCount() {
// better to use coroutines than executors
Executors.newSingleThreadExecutor().execute {
postValue(
MyRoomDatabase.getInstance(applicationContext).OrderDao()
.getOrderCount_()
)
}
}
}
@Transaction
private fun getOrdersCount_(): LiveData<Int>
{
val now = LocalDateTime.now()
val firstOfMonth = now.withDayOfMonth(1)
subop_pruning(firstOfMonth) // query that deletes older orders
return subop_select_count() // query that returns the number of orders
}
使用@Transaction 注解时将LiveData 更改为MutableLiveData。
我知道已经很晚了。但是,仍然有一些人可以从中受益。
我想从旧记录中删除一个 table,然后计算其中的记录数。
@Transaction
private fun getOrdersCount(): LiveData<Int>
{
val now = LocalDateTime.now()
val firstOfMonth = now.withDayOfMonth(1)
subop_pruning(firstOfMonth) // query that deletes older orders
return subop_select_count() // query that returns the number of orders
}
不幸的是,这个查询 return 是一个错误
error: Method annotated with @Transaction must not return deferred/async return type androidx.lifecycle.LiveData. Since transactions are thread confined and Room cannot guarantee that all queries in the method implementation are performed on the same thread, only synchronous @Transaction implemented methods are allowed. If a transaction is started and a change of thread is done and waited upon then a database deadlock can occur if the additional thread attempts to perform a query. This restrictions prevents such situation from occurring.
现在,我想在一个事务中按顺序执行 -delete- 和 -select count- 操作序列,return 来自 -select 的 LiveData计数操作。这在我看来是合法的。 问题:
- 事务中的查询不是顺序执行的吗?
- 为什么会出错?
- 如果无法从交易中获取 LiveData,如何获得相同的行为,例如使用
MutableLiveData
和InvalidationTracker.Observer#onInvalidated
通知?
第 1 点和第 2 点仍未得到解答,无论如何我是如何绕过这个问题的(根据第 3 点)。希望对某人有所帮助:
fun getOrderCount(): LiveData<Int> = object : LiveData<Int>(0) {
val observer = object : InvalidationTracker.Observer("order_table") {
override fun onInvalidated(tables: MutableSet<String>) {
requestOrderCount()
}
}
override fun onActive() {
super.onActive()
val tracker =
MyRoomDatabase.getInstance(applicationContext).invalidationTracker;
tracker.addObserver(observer)
requestOrderCount()
}
override fun onInactive() {
super.onInactive()
val tracker =
MyRoomDatabase.getInstance(applicationContext).invalidationTracker;
tracker.removeObserver(observer)
}
private fun requestOrderCount() {
// better to use coroutines than executors
Executors.newSingleThreadExecutor().execute {
postValue(
MyRoomDatabase.getInstance(applicationContext).OrderDao()
.getOrderCount_()
)
}
}
}
@Transaction
private fun getOrdersCount_(): LiveData<Int>
{
val now = LocalDateTime.now()
val firstOfMonth = now.withDayOfMonth(1)
subop_pruning(firstOfMonth) // query that deletes older orders
return subop_select_count() // query that returns the number of orders
}
使用@Transaction 注解时将LiveData 更改为MutableLiveData。 我知道已经很晚了。但是,仍然有一些人可以从中受益。