Realm从不正确的线程访问

背景

我在我的应用程序中使用Realm。 当数据加载后,它会经历强烈的处理,因此处理发生在后台线程上。

正在使用的编码模式是工作单元模式,Realm只存在于DataManager下的存储库中。 这里的想法是每个存储库可以有不同的数据库/文件存储解决方案。

我所尝试过的

下面是我在FooRespository类中的一些类似代码的例子。

这里的想法是获得Realm的一个实例,用于查询感兴趣对象的领域,返回它们并关闭领域实例。 请注意,这是同步的,并在最后将对象从Realm复制到非托管状态。

public Observable<List<Foo>> getFoosById(List<String> fooIds) {

    Realm realm = Realm.getInstance(fooRealmConfiguration);

    RealmQuery<Foo> findFoosByIdQuery = realm.where(Foo.class);

    for(String id : fooIds) {

        findFoosByIdQuery.equalTo(Foo.FOO_ID_FIELD_NAME, id);
        findFoosByIdQuery.or();
    }

    return findFoosByIdQuery
            .findAll()
            .asObservable()
            .doOnUnsubscribe(realm::close)
            .filter(RealmResults::isLoaded)
            .flatMap(foos -> Observable.just(new ArrayList<>(realm.copyFromRealm(foos))));
}

此代码稍后通过RxJava与重处理代码一起使用:

dataManager.getFoosById(foo)
            .flatMap(this::processtheFoosInALongRunningProcess)
            .subscribeOn(Schedulers.io()) //could be Schedulers.computation() etc
            .subscribe(tileChannelSubscriber);

阅读完文档后,我的信念是上述应该可以工作,因为它不是异步的,因此不需要循环线程。 我在同一个线程中获得领域的实例,因此它不在线程之间传递,也不是对象。

问题

当以上执行我得到

Realm从不正确的线程访问。 领域对象只能在创建它们的线程上访问。

这看起来不正确。 我唯一能想到的就是Realm实例池正在让我使用主线程从另一个进程创建的现有实例。


凯如此

return findFoosByIdQuery
        .findAll()
        .asObservable()

这发生在UI线程上,因为那是你从最初调用它的地方

.subscribeOn(Schedulers.io())

Aaaaand然后你在Schedulers.io()上修补它们。

不,这不是一回事!

尽管我不喜欢从零拷贝数据库复制的方法,但是您当前的方法充斥着由于滥用realmResults.asObservable()而导致的问题,因此,您的代码应该是:

public Observable<List<Foo>> getFoosById(List<String> fooIds) {
   return Observable.defer(() -> {
       try(Realm realm = Realm.getInstance(fooRealmConfiguration)) { //try-finally also works
           RealmQuery<Foo> findFoosByIdQuery = realm.where(Foo.class);
           for(String id : fooIds) {
               findFoosByIdQuery.equalTo(FooFields.ID, id);
               findFoosByIdQuery.or(); // please guarantee this works?
           }
           RealmResults<Foo> results = findFoosByIdQuery.findAll();
           return Observable.just(realm.copyFromRealm(results));
       }
   }).subscribeOn(Schedulers.io());
}

请注意,您正在所有RxJava处理管道之外创建实例。 因此,在调用getFoosById()时,主线程(或任何线程getFoosById()

仅仅因为该方法返回一个Observable并不意味着它在另一个线程上运行。 只有由getFoosById()方法的最后一条语句创建的Observable的处理管道在正确的线程( filter()flatMap()和调用者完成的所有处理)上运行。

因此,您必须确保调用getFoosById()已在Schedulers.io()所使用的线程上完成。

实现这一点的一种方法是使用Observable.defer()

Observable.defer(() -> dataManager.getFoosById(foo))
            .flatMap(this::processtheFoosInALongRunningProcess)
            .subscribeOn(Schedulers.io()) //could be Schedulers.computation() etc
            .subscribe(tileChannelSubscriber);
链接地址: http://www.djcxy.com/p/93405.html

上一篇: Realm access from incorrect thread

下一篇: why Firefox runs this code 10x faster than Chrome