如何使用RxJava从Android Room数据库选择查询返回

时间:2018-01-26 17:18:53

标签: android rx-java rx-android android-room

这是我的查询

@Query("SELECT EXISTS(SELECT 1 FROM media2 WHERE path = :path AND isFav = 1 LIMIT 1)")
    int checkIsFav(String path);

从存储库调用

public boolean checkIsFav(String path) {
    return mDatabase.favDAO().checkIsFav(path) == 1;
}

这有时会导致以下错误

 java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.

我明白为什么,但我需要一个返回才能确定项目是否为收藏。

我将RXjava用于其他数据库操作,但它们不需要返回。

Observable.fromCallable(() -> mDatabase.favDAO().checkIsFav(path) == 1);

Observable.just(mDatabase)
            .subscribeOn(Schedulers.io())
            .subscribe(db -> db.favDAO().insertMedia2(media));

我在片段中使用此方法

            if (mediaViewModel.checkIsFav(media.getPath())){
                mediaViewModel.removeFav(media.getPath());
            } else {
                media.setFav(true);
                mediaViewModel.addFav(media);
            }

和回收器适配器。

 boolean isfav = ((App)context.getApplicationContext()).getRepository().checkIsFav(currentItem.getPath());

运行此查询时获取回调的最简单方法是什么?

更新了单一问题:

这是我在Dao中的查询

@Query("SELECT EXISTS(SELECT 1 FROM media2 WHERE path = :path AND isFav = 1 LIMIT 1)")
Single<Integer> checkIsFav(String path);

我在存储库中的方法

public Single<Integer> checkIsFav(String path){
    return mDatabase.favDAO().checkIsFav(path);
}

我需要从我的适配器和我的片段进行此调用。如何调用它会是这样的?

((App)context.getApplicationContext()).getRepository().checkIsFav(media.getPath()).subscribeOn(
                            ((App)context.getApplicationContext()).getRepository().checkIsFav(media.getPath()).subscribeOn(
                Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(
                new SingleObserver<Integer>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onSuccess(Integer integer) {

                    }

                    @Override
                    public void onError(Throwable e) {

                    }
                });

这似乎并不合适。在我转换到房间之前,这是我的电话

if (App.favDB.existFav(currentItem.getPath()))

在我的SQLiteOpenHelper

中触发了这个
 public boolean existFav(String path) {
        SQLiteDatabase db = getReadableDatabase();
        Cursor cur = db.rawQuery(
            String.format("SELECT EXISTS(SELECT 1 FROM %s WHERE %s=? LIMIT 1)", TABLE_NAME, MEDIA_PATH),
            new String[]{ path });
        boolean tracked = cur.moveToFirst() &&  cur.getInt(0) == 1;
        cur.close();
        return tracked;
    }

也许我没有正确思考这个问题。

我所要做的就是确定这张媒体是否存在于我的表格中。

5 个答案:

答案 0 :(得分:2)

我认为你应该在主线程中观察你的数据。所以使用

observeOn(AndroidSchedulers.mainThread()).

尝试将其更改为

Observable.just(mDatabase)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread()) 
        .subscribe(db -> db.favDAO().insertMedia2(media));

另见observeOn()

上的这个notes

答案 1 :(得分:0)

尝试更改:

@Query("SELECT EXISTS(SELECT 1 FROM media2 WHERE path = :path AND isFav = 1 LIMIT 1)")
int checkIsFav(String path);

为:

@Query("SELECT EXISTS(SELECT 1 FROM media2 WHERE path = :path AND isFav = 1 LIMIT 1)")
Single<Integer> checkIsFav(String path);

使用RxJava with Room有效,但我没有尝试使用SELECT EXISTS,所以YMMV。

答案 2 :(得分:0)

您应该添加到build.gradle

实施'android.arch.persistence.room:rxjava2:version'

关于每种类型的行为方式,请查看此媒体帖子https://medium.com/google-developers/room-rxjava-acb0cd4f3757

答案 3 :(得分:0)

呃,你以前总是在UI线程上读这个。现在Room默认强制执行,因为它可能会阻止UI线程。

如果您不想关心此限制并且只想让旧类型的代码正常工作,则可以使用RoomDatabase.Builder's allowMainThreadQueries()

否则,只需暴露Flowable并订阅Io,就像通常那样在Ui上观察。

答案 4 :(得分:0)

我们可以像这样创建Single:

 public Single<SomeObject> getSomeObjectFromDB(Session session) {
                    return createAsyncSingle(() -> database.getSomeDao().getSomeObject())
.subscribeOn(Schedulers.io()) // We can move it on upper level;
            }

其中:

protected <T> Single<T> createAsyncSingle(final Callable<T> func) {
return Single.create(emitter -> {
            try {
                T result = func.call();
                if(result != null) {
                    emitter.onSuccess(result);
                } else {
                    emitter.onError(new NullPointerException("Empty result from DB"));
                }
            } catch (Exception ex) {
                Logger.e("TAG", "Error operation with DB");
            }
        });
}