【问题标题】:How to return a Rx Single transaction using Room Db?如何使用 Room Db 返回 Rx Single 交易?
【发布时间】:2019-04-01 20:47:13
【问题描述】:
假设有一个Dao 类有以下两个方法:
1)
delete(items: List<Item>): Completable
2)
insert(items: List< Item >): Single<List<Long>>
如何将它们链接到 Dao 类中的 @transaction 方法中,从“删除方法”开始,然后返回“插入方法”结果?
我想要一个带有这样签名的方法:
@Transaction
fun deleteAndInsert(): Single<List<Long> > {
...
}
【问题讨论】:
标签:
android
rx-java2
android-room
【解决方案1】:
我假设您的主要目标是将deleteAndInsert() 的返回类型设为Single。
您只需稍作修改即可实现这一目标
- 首先使
delete() 和insert() 函数同步。
- 由于
@Transaction 只能同步工作,我们需要创建另一个同时调用delete() 和insert() 的函数。另外,用@Transaction注释这个函数
- 创建另一个新函数,该函数创建
Single 并调用上述函数。
abstract class SampleDao{
protected abstract fun delete()
protected abstract fun insert(items: List<Item>) : List<Long>
@Transaction
protected open fun deleteAndInsertSync(items: List<Item>): List<Long>{
delete()
return insert(items)
}
fun deleteAndInsert(items:List<Item>): Single<List<Long>>{
return Single.create {
it.onSuccess(deleteAndInsertSync(items))
}
}
}
【解决方案2】:
我认为这是不可能的。
我曾经尝试过,但出现编译时错误:
"用@Transaction注解的方法不能返回deferred/async
返回类型 io.reactivex.Single。由于事务是线程
限制和房间不能保证方法中的所有查询
实现都是在同一个线程上执行的,只有同步的
允许使用 @Transaction 实现的方法。如果交易是
启动并完成线程更改并等待数据库
如果附加线程尝试执行
询问。此限制可防止此类情况发生。”
【解决方案3】:
- 用@Transaction 注释的方法不能返回延迟/异步返回类型io.reactivex.Single。由于事务是线程受限的,Room 不能保证方法实现中的所有查询都在同一个线程上执行,因此只允许同步 @Transaction 实现的方法。如果启动事务并且完成并等待线程更改,则如果附加线程尝试执行查询,则可能发生数据库死锁。此限制可防止此类情况发生。
-
当我将代码反编译为 java 时,我看到了。
public interface CustomerDao {
@Transaction
@NotNull
List deleteAndCreate(@NotNull List var1);
@Query("DELETE FROM customer")
@NotNull
Completable deleteAll();
@Insert
@NotNull
List insertAll(@NotNull List var1);
@Metadata(
mv = {1, 1, 15},
bv = {1, 0, 3},
k = 3
)
public static final class DefaultImpls {
@Transaction
@NotNull
public static List deleteAndCreate(CustomerDao $this, @NotNull List
users)
{
Intrinsics.checkParameterIsNotNull(users, "users");
$this.deleteAll();
return $this.insertAll(users);
}
}
}
【解决方案4】:
获取新数据的 ID
然后删除所有不在新数据中的项目
@Query("DELETE FROM product WHERE id NOT IN(:idsNewItems)")
@Override
public abstract void deleteOldItems(List<String> idsNewItems)
;
【解决方案5】:
如果您的delete 和insert 方法标有注释,则它们正在事务中执行。所以,基本上你不需要用这个注解来标记你的deleteAndInsert 方法。所以,比:
fun deleteAndInsert(items: List< Item >): Single<List<Long>> {
return delete().andThan(insert(items))
}