Android Room中的交易与RxJava2
作者:互联网
我的应用程序的一个要求是允许用户进行多个步骤,然后在完成时根据每个步骤中的条目将值写入数据库. UI中的每个步骤都可能有助于需要写入数据库的操作.数据可以在多个表中,并且属于这些表中的不同行.如果任何数据库操作失败,则整个操作应该失败.
我最初考虑将所有数据加载到内存中,操作它,然后简单地在每个可能的实体中调用更新方法(冲突策略为REPLACE),但内存中可能存在极大量的数据.
我认为我可以组装一个List,其中显示中的每个Fragment贡献一个或多个Completables,然后在UI流程结束时使用Completable.concat()顺序执行.它看起来如下所示:
Completable one = Completable.fromAction(() -> Log.w(LOG_TAG, "(1)")).delay(1, TimeUnit.SECONDS);
Completable two = Completable.fromAction(() -> Log.w(LOG_TAG, "(2)")).delay(2, TimeUnit.SECONDS);
Completable three = Completable.fromAction(() -> Log.w(LOG_TAG, "(3)")).delay(3, TimeUnit.SECONDS);
Completable four = Completable.fromAction(() -> Log.w(LOG_TAG, "(4)")).delay(3, TimeUnit.SECONDS);
Completable.concatArray(one, two, three, four)
.doOnSubscribe(__ -> {
mRoomDatabase.beginTransaction();
})
.doOnComplete(() -> {
mRoomDatabase.setTransactionSuccessful();
})
.doFinally(() -> {
mRoomDatabase.endTransaction();
})
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe();
Completables实际上是Room DAO插入/更新/删除方法的包装器.我可能还会在完成后执行UI操作,这就是我在主线程上观察的原因.
当我执行此代码时,我得到这些日志:
W/MyPresenter: Begin transaction.
W/MyPresenter: (1)
W/MyPresenter: (2)
W/MyPresenter: (3)
W/MyPresenter: (4)
W/MyPresenter: Set transaction successful.
W/MyPresenter: End transaction.
W/System.err: java.lang.IllegalStateException: Cannot perform this operation because there is no current transaction.
W/System.err: at android.database.sqlite.SQLiteSession.throwIfNoTransaction(SQLiteSession.java:915)
W/System.err: at android.database.sqlite.SQLiteSession.endTransaction(SQLiteSession.java:398)
W/System.err: at android.database.sqlite.SQLiteDatabase.endTransaction(SQLiteDatabase.java:524)
W/System.err: at android.arch.persistence.db.framework.FrameworkSQLiteDatabase.endTransaction(FrameworkSQLiteDatabase.java:88)
W/System.err: at android.arch.persistence.room.RoomDatabase.endTransaction(RoomDatabase.java:220)
W/System.err: at ...lambda$doTest$22$MyPresenter(MyPresenter.java:490)
到达最终时,为什么交易消失了?我也欢迎任何关于这种方法的质量或可行性的评论,因为我对RxJava和Room都很新.
解决方法:
通过记录当前线程并仔细阅读Android开发人员documentation,我想我终于可以理解我做错了什么.
1)事务必须在同一个线程上进行.这就是为什么它告诉我没有交易;我显然在线程之间蹦蹦跳跳.
2)doOnSubscribe,doOnComplete和doFinally方法是side effects,因此不是实际流本身的一部分.这意味着它们不会出现在我订阅的调度程序上.它们将出现在我观察到的调度程序上.
3)因为我想在完成后在UI线程上接收结果,但是想要在后台线程上发生副作用,我需要改变我观察的位置.
Completable.concatArray(one, two, three, four)
.observeOn(Schedulers.single()) // OFF UI THREAD
.doOnSubscribe(__ -> {
Log.w(LOG_TAG, "Begin transaction. " + Thread.currentThread().toString());
mRoomDatabase.beginTransaction();
})
.doOnComplete(() -> {
Log.w(LOG_TAG, "Set transaction successful." + Thread.currentThread().toString());
mRoomDatabase.setTransactionSuccessful();
})
.doFinally(() -> {
Log.w(LOG_TAG, "End transaction." + Thread.currentThread().toString());
mRoomDatabase.endTransaction();
})
.subscribeOn(Schedulers.single())
.observeOn(AndroidSchedulers.mainThread()) // ON UI THREAD
.subscribeWith(new CompletableObserver() {
@Override
public void onSubscribe(Disposable d) {
Log.w(LOG_TAG, "onSubscribe." + Thread.currentThread().toString());
}
@Override
public void onComplete() {
Log.w(LOG_TAG, "onComplete." + Thread.currentThread().toString());
}
@Override
public void one rror(Throwable e) {
Log.e(LOG_TAG, "onError." + Thread.currentThread().toString());
}
});
日志记录语句现在如下所示:
W/MyPresenter: onSubscribe.Thread[main,5,main]
W/MyPresenter: Begin transaction. Thread[RxSingleScheduler-1,5,main]
W/MyPresenter: (1)
W/MyPresenter: (2)
W/MyPresenter: (3)
W/MyPresenter: (4)
W/MyPresenter: Set transaction successful.Thread[RxSingleScheduler-1,5,main]
W/MyPresenter: End transaction.Thread[RxSingleScheduler-1,5,main]
W/MyPresenter: onComplete.Thread[main,5,main]
我相信这可以实现我所追求的目标,但是基于房间的RxJava Completables的逐步组装是否会成功还有待观察.我会密切留意任何意见/答案,并可能为后代报告.
标签:rx-java2,android-room,android,rx-java 来源: https://codeday.me/bug/20190828/1748256.html