我有一个在我的活动中创建的领域对象。我需要能够在我创建的服务中访问此对象。但是,我在服务中创建Realm对象时遇到错误
mRealm = Realm.getInstance(getApplicationContext());
java.lang.IllegalStateException:从错误的线程访问Realm。 Realm对象只能在创建它们的线程上访问
现在我明白这意味着因为领域对象是在我的活动上创建的,所以我无法从后台线程访问它。但是,除了创建自己的自定义处理程序线程之外,我没有找到一个简单的方法,但这似乎是一种笨重的方式。
我在这里遗漏了什么,或者是否真的没有更好的方法可以从不同的线程中访问Realm对象?
更新
我进一步深入研究,在IntentService中,onHandleIntent方法在一个单独的线程中运行,而不是在类中的其他方法。因此,我无法创建类级别的Realm实例,并且能够与onHandleIntent方法的内部和外部进行交互。这就是造成线程异常的原因。除了在每个方法中创建一个单独的Realm实例,我需要访问该对象并一遍又一遍地检索它,我认为Ilya Tretyakov的答案将是最好的。我可以在构造函数中从域中复制对象,然后在服务的整个生命周期中使用它。任何需要回写Realm对象的方法都需要在该方法中实例化自己的Realm实例。
答案 0 :(得分:6)
您可以尝试使用from celery import current_app
current_app.send_task("app.tasks.add", ["param1", "param2"])
。这些方法将Realm数据复制到普通的Java对象中,并将它们从Realm中分离出来。
以下是使用示例:
realm.copyFromRealm(youRealmObject);
以下是来自docs的信息:
创建一个已经存在的RealmObject的独立内存副本。 这是一个深层副本,将复制所有引用的对象。复制了 对象都与Realm分离,因此它们将不再存在 自动更新。这意味着复制的对象可能 包含不再与其他托管Realm一致的数据 对象。 警告:可以合并对复制对象的任何更改 使用copyToRealmOrUpdate(RealmObject)进入Realm,但所有字段都会 被覆盖,而不仅仅是被改变的那些。这包括 对其他对象的引用,可能会覆盖所做的更改 通过其他线程。
https://realm.io/docs/java/latest/api/io/realm/Realm.html#copyFromRealm-E-
答案 1 :(得分:6)
从技术上讲,您应该在后台线程的开头打开Realm实例,在该后台执行结束时关闭它,然后将其传递给中间的方法。
public void handleIntent() { // or doInBackground etc
Realm realm = null;
try {
realm = Realm.getDefaultInstance();
....
MyObj obj = realm.where(MyObj.class)
.equalTo(MyObjFields.ID, myObjId)
.findFirst(); // get by id
....
} finally {
if(realm != null) {
realm.close(); // important
}
}
}
使用realm.copyFromRealm()
是一种解决方法,而不是解决方案。
使用AS 3.0,无论你的minSDK是什么,你都可以使用try-with-resources
(就像你使用Retrolambda一样):
public void handleIntent() { // or doInBackground etc
try(Realm realm = Realm.getDefaultInstance()) {
....
MyObj obj = realm.where(MyObj.class)
.equalTo(MyObjFields.ID, myObjId)
.findFirst(); // get by id
....
} // auto-close
}