Realm access from incorrect thread Exception while a copy was sent using copyFromRealm

一曲冷凌霜 提交于 2019-12-12 10:50:28

问题


When streaming copy of realm objects instead of realm reference and observing it on Schedulers.IO thread, there is a crash with the famous exception message "Realm access from incorrect thread. Realm objects can only be accessed in the thread they were created."

Shouldn't the copy be thread free? Can I produce it from one thread and process it on a different thread?

This is how I am creating observable.

 public Observable<Brand> getAllBrands() {
    return realm.where(Brand.class)
            .findAll()
            .asObservable()
            .flatMap(Observable::from)
            .map(brand -> realm.copyFromRealm(brand));
}

Following is how I observe getAllBrands().

 Observable<Brand> brandObservable = dataManager.getAllBrands();

    brandObservable.observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.io())
            .subscribe(new Observer<Brand>() {
                @Override
                public void onCompleted() {
                    Log.d("reactive", "completed");
                }

                @Override
                public void onError(Throwable e) {
                    Log.d("reactive", e.getMessage());
                }

                @Override
                public void onNext(Brand brand) {
                    dataSource.add(brand.getName());
                    myAdapter.notifyDataSetChanged();
                }
            });

回答1:


You are subscribing on schedulers.io while using the Realm instance from the UI thread:

realm.where(Brand.class)
        .findAll()
        .asObservable()
        .flatMap(Observable::from)
        .map(brand -> realm.copyFromRealm(brand)) // realm instance on the wrong thread
        .subscribeOn(schedulers.io());            

What are you after is an easy way to move a query across threads, which is still work-in-progress here: https://github.com/realm/realm-java/pull/1978. Until then you can work around it by doing it yourself like this:

public Observable<Brand> getAllBrands(final Realm realm) {
    return Observable.create(new Observable.OnSubscribe<List<Brand>>() {
        @Override
        public void call(final Subscriber<? super List<Brand>> subscriber) {
            Realm obsRealm = Realm.getInstance(realm.getConfiguration());
            final RealmResults<Brand> results = obsRealm.where(Brand.class).findAll();
            final RealmChangeListener listener = new RealmChangeListener() {
                @Override
                public void onChange() {
                    subscriber.onNext(realm.copyFromRealm(results));
                }
            };
            results.addChangeListener(listener);
            subscriber.add(Subscriptions.create(new Action0() {
                @Override
                public void call() {
                    realm.removeChangeListener(listener);
                    realm.close();
                }
            }));

        }
    })
    .flatMap(Observable::from);
}

Note that Realm Changelisteners only work on Looper threads which means you probably need to change your worker thread to a H

HandlerThread bgThread = new HandlerThread("workerThread");
Handler handler = new Handler(bgThread.getLooper());

getAllBrands(realm).subscribeOn(HandlerScheduler.from(handler));



回答2:


QUESTION

Can I produce it from one thread and process it on a different thread?

Answer is NO. You can read the description of realm in here

Although Realm files can be accessed by multiple threads concurrently, you cannot hand over Realms, Realm objects, queries, and results between threads. The thread example shows how to use Realm in a multithreading environment.



来源:https://stackoverflow.com/questions/35835858/realm-access-from-incorrect-thread-exception-while-a-copy-was-sent-using-copyfro

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!