2

我在 DataManager 中创建了一个方法,它首先从缓存中下载数据,然后从服务器 API 请求数据,保存结果并将给定的网络数据发送给演示者(在 MVP 中)。

问题是当我想在后台线程上使用 Realm 时,它发生在 UI 线程上。我发现了一些关于第一个 RxJava 领域支持的文章,但我们正在使用具有另一个 API 的第二个版本,所以这些领域方法对我们没有帮助(toObservable())。

如何解决问题?

此外,正如我所看到的,所有其他方法都在 IO 线程上处理,并且只有 Realm 在 Ui 上工作,而不管我把subscribeOn(Schedulers.io()). 为什么会发生?

@Override
public Observable<ChatsRepoAnswerModel> getChats() {
    return getChatsFromCache(STATUS_OK)
            .subscribeOn(Schedulers.io())
            .mergeWith(
                    getChatsService()
                            .getChats()
                            .subscribeOn(Schedulers.io())
                            .map(ChatResponseModel::getResult)
                            .flatMap(mChatsMapper::transformAll)
                            .doOnNext(this::saveChats)
                            .doOnNext(Collections::sort)                            
                            .onErrorResumeNext(getChatsFromCache(STATUS_ERROR))                               
            .observeOn(AndroidSchedulers.mainThread());
}


private void saveChats(List<ChatDataModel> realmObjects) {        
    Realm.getDefaultInstance().executeTransaction(realm -> {
        realm.insertOrUpdate(realmObjects);
    });
}

private Observable<ChatsRepoAnswerModel> getChatsFromCache(int aStatus) {
    Realm realm = Realm.getDefaultInstance();
    RealmResults<ChatDataModel> chats = realm.where(ChatDataModel.class).findAll();
    return processChatResponse(realm.copyFromRealm(chats), aStatus);
}
4

1 回答 1

2

好吧,虽然我认为这完全无视 Realm 试图给你的零拷贝设计:

  • 来自Realm 提供的自动更新响应式数据集的单向数据流,形式为RealmResults(意味着当数据集更改时通知您)
  • 惰性求值,只读取一次访问的元素,RealmResults只是一个“游标”,RealmObject仅在调用访问器时读取数据
  • 一致性:所有托管 RealmProxies 都指向同一个对象,因此您在任何地方都没有“过时”的数据(嗯,除了保留的非自动更新后台线程,但这通常是用户错误)

这很有趣,因为realm.copyFromRealm()创建了通常不具有这些属性的非托管对象:

  • 不再自动更新
  • 急切地评估整个数据集并将所有数据复制到字段中
  • 因此,不一定在所有使用的地方都是最新的

无论如何,在后台线程上创建分离的 RealmObjects 的解决方案是在该线程上打开实例,复制数据集,然后关闭实例。

Observable.fromCallable(() -> { // <-- defer to whatever thread you're running it on
        try(Realm realm = Realm.getDefaultInstance()) {
            return realm.copyFromRealm(realm.where(Cat.class).findAll());
        } // <-- auto-close
    })
.subscribeOn(Schedulers.whatever());

不过,通常按预期使用 Realm 会更容易,尤其是对于较大的数据集。只有通过在后台循环线程 (HandlerThread) 上运行 Realm 来保留自动更新,复制才真正有意义。

于 2017-01-20T09:24:51.407 回答