Android 安卓领域+;RxJava-从错误线程进行领域访问。领域对象只能在创建它们的线程上访问
我正在尝试实现RxJava+领域+改造+存储库模式 以下是我的本地实现:Android 安卓领域+;RxJava-从错误线程进行领域访问。领域对象只能在创建它们的线程上访问,android,multithreading,realm,rx-java,Android,Multithreading,Realm,Rx Java,我正在尝试实现RxJava+领域+改造+存储库模式 以下是我的本地实现: @Override public Observable<Page> search(@NonNull final String query) { return Realm.getDefaultInstance().where(Page.class) .equalTo("query", query) .findAll()
@Override
public Observable<Page> search(@NonNull final String query) {
return Realm.getDefaultInstance().where(Page.class)
.equalTo("query", query)
.findAll()
.asObservable()
.cast(Page.class);
}
@Override
public Observable<Page> search(@NonNull String query) {
return mWikiServices.search(query).map(new Func1<Result, Page>() {
@Override
public Page call(Result result) {
final List<Page> pages = new ArrayList<>(result.getQuery().getPages().values());
return pages.get(0);
}
});
}
final Observable<Page> localResult = mSearchLocalDataSource.search(query);
final Observable<Page> remoteResult = mSearchRemoteDataSource.search(query)
.doOnNext(new Action1<Page>() {
@Override
public void call(Page page) {
//mSearchLocalDataSource.save(query, page);
//mResultCache.put(query, page);
}
});
return Observable.concat(localResult, remoteResult)
.first()
.doOnError(new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
throwable.printStackTrace();
}
});
@Override
public Observable<Page> search(@NonNull String query) {
return mWikiServices.search(query).flatMap(new Func1<Result, Observable<Page>>() {
@Override
public Observable<Page> call(Result result) {
final ArrayList<Page> pages = new ArrayList<>(result.getQuery().getPages().values());
Log.i("data from", "remote");
return Observable.from(pages).first();
}
});
}
@Override
public Observable<Page> search(@NonNull final String query) {
return Observable.create(new Observable.OnSubscribe<Page>() {
@Override
public void call(Subscriber<? super Page> subscriber) {
final Realm realm = Realm.getInstance(mRealmConfiguration);
final Page page = realm.where(Page.class)
.equalTo("query", query)
.findFirst();
if (page != null && page.isLoaded() && page.isValid()) {
Log.i("data from", "realm");
subscriber.onNext(realm.copyFromRealm(page));
} else {
Observable.empty();
}
subscriber.onCompleted();
realm.close();
}
});
}
@覆盖
公共可观察搜索(@NonNull final String query){
返回Realm.getDefaultInstance().where(Page.class)
.equalTo(“查询”,查询)
.findAll()
.asObservable()
.cast(Page.class);
}
以下是我的远程实现:
@Override
public Observable<Page> search(@NonNull final String query) {
return Realm.getDefaultInstance().where(Page.class)
.equalTo("query", query)
.findAll()
.asObservable()
.cast(Page.class);
}
@Override
public Observable<Page> search(@NonNull String query) {
return mWikiServices.search(query).map(new Func1<Result, Page>() {
@Override
public Page call(Result result) {
final List<Page> pages = new ArrayList<>(result.getQuery().getPages().values());
return pages.get(0);
}
});
}
final Observable<Page> localResult = mSearchLocalDataSource.search(query);
final Observable<Page> remoteResult = mSearchRemoteDataSource.search(query)
.doOnNext(new Action1<Page>() {
@Override
public void call(Page page) {
//mSearchLocalDataSource.save(query, page);
//mResultCache.put(query, page);
}
});
return Observable.concat(localResult, remoteResult)
.first()
.doOnError(new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
throwable.printStackTrace();
}
});
@Override
public Observable<Page> search(@NonNull String query) {
return mWikiServices.search(query).flatMap(new Func1<Result, Observable<Page>>() {
@Override
public Observable<Page> call(Result result) {
final ArrayList<Page> pages = new ArrayList<>(result.getQuery().getPages().values());
Log.i("data from", "remote");
return Observable.from(pages).first();
}
});
}
@Override
public Observable<Page> search(@NonNull final String query) {
return Observable.create(new Observable.OnSubscribe<Page>() {
@Override
public void call(Subscriber<? super Page> subscriber) {
final Realm realm = Realm.getInstance(mRealmConfiguration);
final Page page = realm.where(Page.class)
.equalTo("query", query)
.findFirst();
if (page != null && page.isLoaded() && page.isValid()) {
Log.i("data from", "realm");
subscriber.onNext(realm.copyFromRealm(page));
} else {
Observable.empty();
}
subscriber.onCompleted();
realm.close();
}
});
}
@覆盖
公共可观察搜索(@NonNull字符串查询){
返回mWikiServices.search(query.map)(new Func1(){
@凌驾
公共页面调用(结果){
最终列表页=新的ArrayList(result.getQuery().getPages().values());
返回页面。获取(0);
}
});
}
以下是我的回购实施:
@Override
public Observable<Page> search(@NonNull final String query) {
return Realm.getDefaultInstance().where(Page.class)
.equalTo("query", query)
.findAll()
.asObservable()
.cast(Page.class);
}
@Override
public Observable<Page> search(@NonNull String query) {
return mWikiServices.search(query).map(new Func1<Result, Page>() {
@Override
public Page call(Result result) {
final List<Page> pages = new ArrayList<>(result.getQuery().getPages().values());
return pages.get(0);
}
});
}
final Observable<Page> localResult = mSearchLocalDataSource.search(query);
final Observable<Page> remoteResult = mSearchRemoteDataSource.search(query)
.doOnNext(new Action1<Page>() {
@Override
public void call(Page page) {
//mSearchLocalDataSource.save(query, page);
//mResultCache.put(query, page);
}
});
return Observable.concat(localResult, remoteResult)
.first()
.doOnError(new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
throwable.printStackTrace();
}
});
@Override
public Observable<Page> search(@NonNull String query) {
return mWikiServices.search(query).flatMap(new Func1<Result, Observable<Page>>() {
@Override
public Observable<Page> call(Result result) {
final ArrayList<Page> pages = new ArrayList<>(result.getQuery().getPages().values());
Log.i("data from", "remote");
return Observable.from(pages).first();
}
});
}
@Override
public Observable<Page> search(@NonNull final String query) {
return Observable.create(new Observable.OnSubscribe<Page>() {
@Override
public void call(Subscriber<? super Page> subscriber) {
final Realm realm = Realm.getInstance(mRealmConfiguration);
final Page page = realm.where(Page.class)
.equalTo("query", query)
.findFirst();
if (page != null && page.isLoaded() && page.isValid()) {
Log.i("data from", "realm");
subscriber.onNext(realm.copyFromRealm(page));
} else {
Observable.empty();
}
subscriber.onCompleted();
realm.close();
}
});
}
final Observable localResult=mSearchLocalDataSource.search(查询);
最终可观察的remoteResult=mSearchRemoteDataSource.search(查询)
.doOnNext(新行动1){
@凌驾
公共作废调用(第页){
//mSearchLocalDataSource.save(查询,页面);
//mResultCache.put(查询,页面);
}
});
返回Observable.concat(localResult、remoteResult)
.first()
.doon错误(新操作1(){
@凌驾
公共无效呼叫(可丢弃可丢弃){
printStackTrace();
}
});
最后是我在presenter中的订阅
final Subscription subscription = mSearchRepository.search(this.mQuery)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Page>() {
@Override
public void onCompleted() {
// Completed
}
@Override
public void onError(Throwable e) {
mView.onDefaultMessage(e.getMessage());
}
@Override
public void onNext(Page page) {
mView.onDefaultMessage(page.getContent());
}
});
mCompositeSubscription.add(subscription);
final Subscription Subscription=mSearchRepository.search(this.mQuery)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.订阅(新观察员){
@凌驾
未完成的公共无效(){
//完成
}
@凌驾
公共无效申报人(可丢弃的e){
mView.onDefaultMessage(e.getMessage());
}
@凌驾
公共void onNext(第页){
mView.onDefaultMessage(page.getContent());
}
});
mcompositionsubscription.add(订阅);
当我运行代码时,我得到这个异常:来自错误线程的领域访问。领域对象只能在创建它们的线程上访问
我在Github repo领域尝试了官方解决方案,但没有一个有效。仍然得到这个例外
我想我得到这个异常是因为我订阅了一个io线程。在主线程中创建领域实例。所以我得到了这个例外
是否有任何实施方案
谢谢。上次编辑:从技术上讲,这两种解决方案都有效,正如Viraj Tank所说的-vs 不过,正确的深度集成方法应该是从服务中单独下载,并有一个用户监听底层领域中的更改。(
realmResults.asObservable().subscribe()
)
老实说,我忍不住觉得这在概念上是有缺陷的 首先,领域查询在创建时在主线程上执行
@Override
public Observable<Page> search(@NonNull final String query) {
return Realm.getDefaultInstance().where(Page.class)
考虑到您似乎不依赖于领域的自动更新功能,您可以考虑使用<代码> Value.CopyOfEngEngEy(ObjixObjix:ObjixObj/Objy>)来创建一个可以在线程之间传递的非托管副本。
但实际上,为了正确地使用领域,您应该有两个订阅-从网络到领域的单个数据流;还有一个订阅
RealmResults.asObservable()
,当网页被网络observable写入到下面时,它会通知你,这就是我们的想法
。因此,如果在RecyclerView中显示多个元素,则甚至不需要可观察的领域,因为RealmRecylerViewAdapter
通过RealmChangeListener
管理其自动更新,而无需依赖asObservable()
来完成
编辑: 在分叉之后,显然我一直都是对的。简单的零拷贝解决方案是为本地可观察对象添加
subscribeOn(AndroidSchedulers.mainThread())
令人惊讶的是,变化不大
final Observable<Page> localResult = mSearchLocalDataSource.search(query).filter(new Func1<Page, Boolean>() {
@Override
public Boolean call(Page page) {
return page != null;
}
}).subscribeOn(AndroidSchedulers.mainThread());
final Observable<Page> remoteResult = mSearchRemoteDataSource.search(query).subscribeOn(Schedulers.io())
.doOnNext(new Action1<Page>() {
@Override
public void call(Page page) {
if (page != null) {
mSearchLocalDataSource.save(query, page);
// mResultCache.put(query, page);
}
}
});
return Observable.concat(localResult, remoteResult)
.first()
.map(new Func1<Page, Page>() {
@Override
public Page call(Page page) {
if (page == null) {
throw new NoSuchElementException("No result found!");
}
return page;
}
});
应替换为以下内容:
@Override
public Observable<Page> search(@NonNull final String query) {
Realm realm = mRealmManager.getRealm(); // UI thread only!
final Page page = realm.where(Page.class).equalTo("query", query).findFirst();
if(page != null) {
Log.i("data from", "realm");
return page.asObservable();
} else {
Log.i("data is", "empty");
return Observable.empty();
}
}
@覆盖
公共可观察搜索(@NonNull final String query){
Realm Realm=mRealmManager.getRealm();//仅限UI线程!
最后一页Page=realm.where(Page.class).equalTo(“query”,query).findFirst();
如果(第页!=null){
Log.i(“来自”、“领域”的数据);
返回页面.asObservable();
}否则{
Log.i(“数据为”、“空”);
return-Observable.empty();
}
}
最后,一些额外的架构设计可以让这一切变得更好,但我想我还是睡一觉吧。最后一次编辑:从技术上讲,这两种解决方案都有效,正如Viraj Tank所说的-vs 不过,正确的深度集成方法应该是从服务中单独下载,并有一个用户监听底层领域中的更改。(
realmResults.asObservable().subscribe()
)
老实说,我忍不住觉得这在概念上是有缺陷的 首先,领域查询在创建时在主线程上执行
@Override
public Observable<Page> search(@NonNull final String query) {
return Realm.getDefaultInstance().where(Page.class)
考虑到您似乎不依赖于领域的自动更新功能,您可以考虑使用<代码> Value.CopyOfEngEngEy(ObjixObjix:ObjixObj/Objy>)来创建一个可以在线程之间传递的非托管副本。
但实际上,为了正确使用领域,您应该有两个订阅-一个dat