Realm + Retrofit + RxJava:Concat和SubscribeOn

时间:2016-09-02 23:01:02

标签: realm retrofit rx-java concat

使用RxJava concat运算符时遇到问题。我有两个observable,第一个从服务器数据库发出结果,另一个从本地数据库发出结果,然后我结束:

// Uses a Realm in the UI thread
Observable<MyResult> remoteObservable = mRemoteDataSource.find(tId);

// Uses Retrofit
Observable<MyResult> localObservable = mLocalDataSource.find(tId);

Observable.concat(localObservable, remoteObservable)
    .doOnNext(result -> /* Do my stuff */)
    .observeOn(AndroidSchedulers.mainThread())
    .doOnError(throwable -> throwable.printStackTrace())
    .subscribe()

所以这会导致我的问题,因为我没有使用subscribeOn()连接的observable正在AndroidScheduler.MainThread()上运行,这不会运行远程并启动NetworkOnMainThreadException

如果我实现subscribeOn(Schedulers.computation())我得到Realm access from incorrect thread. Realm objects can only be accessed on the thread they were created,因为当然Observable没有在Realm实例存在的线程上运行。

我已经搜索了其他问题并且我没有得到任何有用的东西,我已经检查了领域做出的例子:https://github.com/realm/realm-java/blob/master/examples/rxJavaExample/src/main/java/io/realm/examples/rxjava/retrofit/RetrofitExample.java但奇怪的是我看到改装的observable没有任何订阅而且它有效。

为什么它对样本起作用,在我的代码中我不能这样做?有什么建议吗?

3 个答案:

答案 0 :(得分:2)

我相信你应该在正确的地方使用subscribeOn()

// Uses a Realm in the UI thread
Observable<MyResult> realmObservable = mRealmDataSource.find(tId).subscribeOn(AndroidSchedulers.mainThread());

// Uses Retrofit
Observable<MyResult> retrofitObservable = mRetrofitDataSource.find(tId).subscribeOn(Subscribers.io());

Observable.concat(realmObservable, retrofitObservable)
    .doOnNext(result -> /* Do my stuff */)
    .subscribeOn(AndroidSchedulers.mainThread())
    .observeOn(AndroidSchedulers.mainThread())
    .doOnError(throwable -> throwable.printStackTrace())
    .subscribe()

看看它是否解决了您的问题。

答案 1 :(得分:2)

您可以连接本地和远程可观察对象,如下所示:

// Uses a Realm in the UI thread
Observable<MyResult> remoteObservable = mRemoteDataSource.find(tId);

// Uses Retrofit
Observable<MyResult> localObservable = mLocalDataSource.find(tId);

Observable.concat(localObservable, remoteObservable).first()
                .map(new Func1<MyResult, MyResult>() {
                    @Override
                    public myResult call(MyResult result) {
                        if (result == null) {
                            throw new IllegalArgumentException();
                        }
                        return result;
                    }
                });

订阅如下:

CompositeSubscription mCompositeSubscription = new CompositeSubscription();
final Subscription subscription = mRepo.find(tId
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<MyResult>() {
                    @Override
                    public void onCompleted() {
                        // Completed
                    }

                    @Override
                    public void onError(Throwable e) {
                        // onError
                    }

                    @Override
                    public void onNext(MyResult result) {
                        //onSuccess
                    }
                });
mCompositeSubscription.add(subscription);

您可以查看此仓库以获取RxJava + Retrofit + Realm https://github.com/savepopulation/wikilight

祝你好运!

答案 2 :(得分:0)

不是在subscribeOn使用mRealmDataSource.find(tId).subscribeOn(AndroidSchedulers.mainThread()) 就像说的那样:https://stackoverflow.com/a/39304891/2425851

您可以使用Observable.defer 例如:

class RealmDataSource{
fun find(id: String): Observable<MyResult> {
// Default pattern for loading data on a background thread
return Observable.defer{
                val realm = Realm.getInstance()

                val query = realm
                    .where(MyResult::class.java)

                val flowable =
                    if (realm.isAutoRefresh) {
                        query
                            .findAllAsync()
                            .asFlowable()
                            .filter(RealmResults::isLoaded)
                    } else {
                        Flowable.just(query.findAll())
                    }

                return@defer flowable
                    .toObservable()
            }
}

然后将不使用subscribeOn

// Uses a Realm
Observable<MyResult> realmObservable = mRealmDataSource.find(tId);

// Uses Retrofit
Observable<MyResult> remoteObservable = mRemoteDataSource.find(tId);

有关更多信息,请参见https://realm.io/blog/realm-java-0-87-0/