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