首页 文章

Rxjava Realm从错误的线程访问

提问于
浏览
2

我正在从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)at 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)ato.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)at java.util.concurrent.FutureTask.run(FutureTask.java:237)at java.util.concurrent.ScheduledThreadPoolExecutor $ Schedul edFutureTask.run(ScheduledThreadPoolExecutor.java:272)java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)java.util.concurrent.ThreadPoolExecutor $ Worker.run(ThreadPoolExecutor.java:607)at 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 -> {
            }));

Read data

private List<CategoryModel> readData() {
    Realm defaultInstance = Realm.getDefaultInstance();
    List<CategoryModel> title = defaultInstance.where(CategoryModel.class).findAllSorted("title");

    defaultInstance.close();
    return title;
}

Write data

private void writeData(List<CategoryModel> categoryModels) {

        try {
            Realm defaultInstance = Realm.getDefaultInstance();
            defaultInstance.executeTransactionAsync(realm -> realm.insertOrUpdate(categoryModels));
            defaultInstance.close();
        } finally {
            getView().notifyActivity(categoryModels);
        }
    }

如何使用正确的线程遵循此逻辑?

4 回答

  • -1

    您只能在事务中操作Realm对象,或者只能在读/写这些对象的线程中操作 . 在您的情况下,您从readData方法获取RealmResult并使用RxJava切换导致异常的线程 . 使用copyFromRealm从realm获取数据,它将它们作为普通对象而不是realm对象返回 .

  • 6

    The only rule to using Realm across threads is to remember that Realm, RealmObject or RealmResults instances cannot be passed across threads .

    如果要从不同的线程访问相同的数据,只需获取 a new Realm instance (即 Realm.getDefaultInstance() )并通过查询获取对象(然后在线程末尾关闭Realm) .

    对象将映射到磁盘上的相同数据,并且可以从任何线程读取和写入!您也可以使用 realm.executeTransactionAsync() (如this)在后台线程上运行代码 .

  • 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;
    }
    

    这样(如果我没有弄乱任何东西),你最终会得到herehere所描述的被动数据层,除非没有映射出整个结果的额外开销 .

    EDIT:

    从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);
        }
    }
    
  • 0

    您需要从领域对象中提取所需的数据到POJO并使用map运算符发出POJO,以便使用Android主线程上的pojo从视图对象中更新 .

相关问题