Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/209.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 从一个领域异步复制到另一个领域_Java_Android_Realm - Fatal编程技术网

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

Java 从一个领域异步复制到另一个领域,java,android,realm,Java,Android,Realm,据我所知,领域只能/应该从主线程访问 我使用两个领域,一个用于存储“脏”数据,在验证后,这些数据将被移动到真实领域 到目前为止还不错,但我无法在主线程之外找到这样做的方法。 如果我使用realm.executeTransactionAsync()写入真实领域,我将无法访问脏领域或其事务线程内的RealmResults 唯一的解决方法是在主线程上使用dirtyRealm.copyFromRealm(),这可能会导致线程阻塞更长时间,对吗 这是正确的方法,还是有更好的解决方案?根据 我认为在这个领域

据我所知,
领域
只能/应该从主线程访问

我使用两个领域,一个用于存储“脏”数据,在验证后,这些数据将被移动到真实领域

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

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


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

根据

我认为在这个领域里并没有标准的方法可以做到这一点。我想在RealmObjectA中创建一个静态函数,比如copyToRealmObjectB,它接受两个参数,一个是RealmObjectA,另一个是RealmObjectB。并在静态函数中调用setter和getter进行复制。很抱歉,这看起来不是一个正常合理的要求。为什么不使用RealmObject字段呢?请参阅realm.io/docs/java/latest/#字段类型

根据我的理解,领域只能/应该从主线程访问

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

如果您想在后台线程上打开一个领域,您可以轻松地执行以下操作:

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();

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

executeTransactionAsync
块中使用简单的同步查询(如
findAll()
)和
realm.copyFromRealm(results)
)-执行不包含写入操作的事务可能不是一个好的做法,但它可以在不需要更改整个代码的情况下完成任务


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

我使用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();
    }

}
公共类RealmCopier{
私有字符串errorLog=“”;
public Completable copyTo(Realm-Realm){//在我的例子中是ROS上的远程领域
返回可完成。创建(发射器->{
布尔值isCopied=copy(领域);
如果(!emitter.isDisposed()){
如果(isCopied)
emitter.onComplete();
其他的
发射器.onError(新的可丢弃(错误日志));
}
});
}
私有布尔复制(领域){
试一试{
realm.beginTransaction();
insertOrUpdate(getItems(SomeClassA.class));
insertOrUpdate(getItems(SomeClassB.class));
realm.commitTransaction();
}捕获(例外e){
realm.cancelTransaction();
errorLog=e.getMessage();
返回false;
}最后{
realm.close();
}
返回true;
}

私有列表据我所知,您提到的注释引用的是将数据从一个ClassA扩展RealmObject复制到ClassB扩展RealmObject,而不使用setter和getter。这不是我的问题,我认为这与线程或使用多个
领域
实例无关,因此它实际上并不重要帮助我。
据我所知,领域只能/应该从主线程访问。
错了,领域只能从创建它的线程访问。@EpicPandaForce这就是为什么我写了“应该”。如果不先将每个
RealmObject
复制到内存副本中,我就不能再在视图中访问它们了。你愿意吗建议?我说,你可以访问在特定线程上打开的域。这并不意味着你不能在UI线程上访问你的UI线程域。但是,你如何将数据从后台域获取到主线程?我认为你需要在后台线程中创建分离的副本,然后以某种方式通知主线程o并获取它们。您好?当您在后台线程上提交时,Realm已经自动执行此操作,并通知RealmChangeListener?您可以让不同的Realm实例在同一个Realm数据库上运行?这确实会更安全。是的。您只需确保在线程执行结束时关闭它们,Primari如果它在后台线程上,那么我将不得不使用多个不同的领域文件,因为我需要将新数据的一部分传输到“live”域,同时仍将其他数据提取到脏域中。但我认为它在主线程中没有任何域I/O的情况下也可以工作,谢谢!我认为您可以使用
Completable.fromAction
而不是
Completable.create
在这里创建
Completable.create
为您提供更大的灵活性来处理您可以捕获/重试的异常我想如果你想从回调发出完成/错误的信号,你应该使用create,而你不是,因此fromAction应该足够了
 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();
    }

}