从一个领域异步复制到另一个领域

时间:2016-11-04 12:28:05

标签: java android realm

根据我的理解,Realm只能从主线程访问。

我使用两个领域,一个用于存储“脏”数据,经过验证,将被移动到真实领域。

到目前为止一直很好,但我无法在主线之外找到这样做的方法。 如果我使用realm.executeTransactionAsync()写入真实域,我将无法在事务线程内访问脏域或其RealmResults

唯一的解决方法是在主线程上使用dirtyRealm.copyFromRealm() - 这可能会阻塞线程更长的时间,对吗?

这是正确的方法还是有更好的解决方案?

4 个答案:

答案 0 :(得分:1)

  

根据我的理解,Realm只能从主线程访问。

这是一种误解。虽然Realm仅在looper线程(例如主线程)上自动更新,但这并不意味着您无法在任何线程上创建新的Realm实例。

如果你想在后台线程上打开一个领域,你可以轻松地做到这一点:

new Thread(new Runnable() {
    @Override
    public void run() {
        Realm firstRealm = null;
        Realm secondRealm = null;
        try {
           firstRealm = Realm.getInstance(firstConfiguration);
           secondRealm = Realm.getInstance(secondConfiguration);

           firstRealm.beginTransaction();
           secondRealm.beginTransaction();
           RealmResults<SomeObject> someObjects = firstRealm.where(SomeObject.class)
                                                            .equalTo(SomeObjectFields.VALID, true)
                                                            .findAll();
           secondRealm.copyToRealmOrUpdate(someObjects); // I am not sure if you have to detach it first.
           someObjects.deleteAllFromRealm();
           secondRealm.commitTransaction();
           firstRealm.commitTransaction();
        } catch(Throwable e) {
           if(firstRealm != null && firstRealm.isInTransaction()) {
               firstRealm.cancelTransaction();
           }
           if(secondRealm != null && secondRealm.isInTransaction()) {
               secondRealm.cancelTransaction();
           }
           throw e;
        } finally {
           if(firstRealm != null) {
              firstRealm.close();
           }
           if(secondRealm != null) {
              secondRealm.close();
           }
        }
    }
}).start();

要访问UI线程上的元素,您只需要一个UI线程Realm和一个绑定了RealmResults的{​​{1}}。

RealmChangeListener

答案 1 :(得分:1)

除了EpicPandaForces答案之外,还可以针对此问题采用快速解决方法:

findAll()块中使用简单的同步查询(如realm.copyFromRealm(results))和executeTransactionAsync - 执行不包含写操作的事务可能不是一个好习惯,但它完成工作而无需更改整个代码。

TLDR;将您的查询和copyFromRealm移动到 executeTransactionAsync 块。

答案 2 :(得分:0)

根据this comment by beeender

,在领域中没有标准的方法
  

我认为在Realm中没有标准的方法可以做到这一点。我想在RealmObjectA中创建一个静态函数,如copyToRealmObjectB,它有两个参数,一个是RealmObjectA,另一个是RealmObjectB。并在静态函数中调用setter和getter来进行复制。对不起,但它看起来不是一个正常而合理的要求。为什么不直接使用RealmObject?请参阅realm.io/docs/java/latest/#field-types

答案 3 :(得分:0)

我使用RxJava Completable在后​​台线程中完成此操作

 public class RealmCopier {

    private String errorLog = "";

    public Completable copyTo(Realm realm) {//in my case remote realm on ROS

        return Completable.create(emitter -> {

            boolean isCopied = copy(realm);

            if (!emitter.isDisposed()){

                if (isCopied)
                    emitter.onComplete();
                else
                    emitter.onError(new Throwable(errorLog));

            }
        });

    }

    private boolean copy(Realm realm) {

        try {
            realm.beginTransaction();

            realm.insertOrUpdate(getItems(SomeClassA.class));
            realm.insertOrUpdate(getItems(SomeClassB.class));

            realm.commitTransaction();

        }catch(Exception e){
            realm.cancelTransaction();
            errorLog = e.getMessage();
            return false;

        } finally {
            realm.close();
        }

        return true;
    }

    private List<? extends RealmObject> getItems(Class<? extends RealmObject> classType) {

        RealmConfiguration localConfiguration = ConfigurationManager.createLocalConfiguration();

        Realm realm = Realm.getInstance(localConfiguration);//local realm

        return realm.where(classType).findAll();
    }

}
相关问题