我从Realm
获得此异常读/写06-19 09:49:26.352 11404-11404 / ****** E / ContentValues:loadData:OnError Realm从错误的线程访问。 Realm对象只能在创建它们的线程上访问。 java.lang.IllegalStateException:从错误的线程访问Realm。 Realm对象只能在创建它们的线程上访问。 at io.realm.BaseRealm.checkIfValid(BaseRealm.java:385) at io.realm.RealmResults.isLoaded(RealmResults.java:115) at io.realm.OrderedRealmCollectionImpl.size(OrderedRealmCollectionImpl.java:307) 在io.realm.RealmResults.size(RealmResults.java:60) at java.util.AbstractCollection.isEmpty(AbstractCollection.java:86) at / ****** .lambda $ loadData $ 0(SplashPresenter.java:42) at / ****** $$ Lambda $ 1.test(未知来源) at io.reactivex.internal.operators.observable.ObservableFilter $ FilterObserver.onNext(ObservableFilter.java:45) at io.reactivex.observers.SerializedObserver.onNext(SerializedObserver.java:111) at io.reactivex.internal.operators.observable.ObservableDelay $ DelayObserver $ 1.run(ObservableDelay.java:84) at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:59) at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:51) 在java.util.concurrent.FutureTask.run(FutureTask.java:237) at java.util.concurrent.ScheduledThreadPoolExecutor $ ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:272) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133) at java.util.concurrent.ThreadPoolExecutor $ Worker.run(ThreadPoolExecutor.java:607) 在java.lang.Thread.run(Thread.java:761)
这是代码:
mSubscribe = Observable.just(readData())
.delay(DELAY, TimeUnit.SECONDS)
.filter(value -> !value.isEmpty())
.switchIfEmpty(createRequest())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()).subscribe(data -> {
getView().hideLoading();
writeData(data);
},
(throwable -> {
}));
读取数据
private List<CategoryModel> readData() {
Realm defaultInstance = Realm.getDefaultInstance();
List<CategoryModel> title = defaultInstance.where(CategoryModel.class).findAllSorted("title");
defaultInstance.close();
return title;
}
写入数据
private void writeData(List<CategoryModel> categoryModels) {
try {
Realm defaultInstance = Realm.getDefaultInstance();
defaultInstance.executeTransactionAsync(realm -> realm.insertOrUpdate(categoryModels));
defaultInstance.close();
} finally {
getView().notifyActivity(categoryModels);
}
}
如何使用正确的线程来遵循此逻辑?
答案 0 :(得分:6)
如果要从不同的线程访问相同的数据,只需获取一个新的Realm实例(即Realm.getDefaultInstance()
)并通过查询获取对象(然后关闭Realm)在线程的最后)。
对象将映射到磁盘上的相同数据,并且可读和可写任何线程!您还可以使用realm.executeTransactionAsync()
if(document.body.contains(yourElement)) {
// Yep, it's attached.
}
在后台线程上运行代码
答案 1 :(得分:2)
我如何使用正确的线程来遵循这个逻辑?
通过不尝试在Schedulers.io()
上读取您的UI线程(Realm提供自动更新延迟加载的代理视图,毕竟在UI线程上为您的数据提供更改通知)。
所以不是这个
mSubscribe = Observable.just(readData())
.delay(DELAY, TimeUnit.SECONDS)
.filter(value -> !value.isEmpty())
.switchIfEmpty(createRequest())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()).subscribe(data -> {
getView().hideLoading();
writeData(data);
},
(throwable -> {
}));
private List<CategoryModel> readData() {
Realm defaultInstance = Realm.getDefaultInstance();
List<CategoryModel> title = defaultInstance.where(CategoryModel.class).findAllSorted("title");
defaultInstance.close();
return title;
}
private void writeData(List<CategoryModel> categoryModels) {
try {
Realm defaultInstance = Realm.getDefaultInstance();
defaultInstance.executeTransactionAsync(realm -> realm.insertOrUpdate(categoryModels));
defaultInstance.close();
} finally {
getView().notifyActivity(categoryModels);
}
}
你应该有像
这样的东西private Observable<List<CategoryModel>> readData() { // Flowable with LATEST might be better.
return io.reactivex.Observable.create(new ObservableOnSubscribe<List<CategoryModel>>() {
@Override
public void subscribe(ObservableEmitter<List<CategoryModel>> emitter)
throws Exception {
final Realm observableRealm = Realm.getDefaultInstance();
final RealmResults<CategoryModel> results = observableRealm.where(CategoryModel.class).findAllSortedAsync("title");
final RealmChangeListener<RealmResults<CategoryModel>> listener = results -> {
if(!emitter.isDisposed() && results.isLoaded()) {
emitter.onNext(results);
}
};
emitter.setDisposable(Disposables.fromRunnable(() -> {
if(results.isValid()) {
results.removeChangeListener(listener);
}
observableRealm.close();
}));
results.addChangeListener(listener);
}
}).subscribeOn(AndroidSchedulers.mainThread())
.unsubscribeOn(AndroidSchedulers.mainThread());
}
private void setSubscription() {
mSubscribe = readData()
.doOnNext((list) -> {
if(list.isEmpty()) {
Single.fromCallable(() -> this::createRequest)
.subscribeOn(Schedulers.io())
.subscribe((data) -> {
writeData(data);
});
}
}).subscribe(data -> {
if(!data.isEmpty()) {
getView().hideLoading();
getView().notifyActivity(data);
}
}, throwable -> {
throwable.printStackTrace();
});
}
private void writeData(List<CategoryModel> categoryModels) {
try(Realm r = Realm.getDefaultInstance()) {
r.executeTransaction(realm -> realm.insertOrUpdate(categoryModels));
}
}
void unsubscribe() {
mSubscribe.dispose();
mSubscribe = null;
}
这种方式(如果我没有弄乱任何东西),你最终得到了here和here所描述的被动数据层,除了没有额外的开销来映射整个结果
修改强>
从Realm 4.0开始,可以直接将RealmResults公开为Flowable(在UI线程或后台循环线程上)。
public Flowable<List<MyObject>> getLiveResults() {
try(Realm realm = Realm.getDefaultInstance()) {
return realm.where(MyObject.class)
.findAllAsync()
.asFlowable()
.filter(RealmResults::isLoaded);
}
}
答案 2 :(得分:0)
您需要从领域对象中提取所需数据到POJO并使用map运算符发出POJO,以便视图对象可以使用来自领域的数据在Android主线程上使用pojo进行更新。
答案 3 :(得分:-1)
您只能在事务中操作Realm对象,或者只能在读/写这些对象的线程中操作。在您的情况下,您从readData方法获取RealmResult并使用RxJava切换导致异常的线程。使用copyFromRealm从realm获取数据,它将它们作为普通对象而不是realm对象返回。