Android领域 - 从服务访问领域对象

时间:2016-02-18 20:44:12

标签: java android multithreading realm

我有一个在我的活动中创建的领域对象。我需要能够在我创建的服务中访问此对象。但是,我在服务中创建Realm对象时遇到错误

        mRealm = Realm.getInstance(getApplicationContext());
  

java.lang.IllegalStateException:从错误的线程访问Realm。   Realm对象只能在创建它们的线程上访问

现在我明白这意味着因为领域对象是在我的活动上创建的,所以我无法从后台线程访问它。但是,除了创建自己的自定义处理程序线程之外,我没有找到一个简单的方法,但这似乎是一种笨重的方式。

我在这里遗漏了什么,或者是否真的没有更好的方法可以从不同的线程中访问Realm对象?

更新

我进一步深入研究,在IntentService中,onHandleIntent方法在一个单独的线程中运行,而不是在类中的其他方法。因此,我无法创建类级别的Realm实例,并且能够与onHandleIntent方法的内部和外部进行交互。这就是造成线程异常的原因。除了在每个方法中创建一个单独的Realm实例,我需要访问该对象并一遍又一遍地检索它,我认为Ilya Tretyakov的答案将是最好的。我可以在构造函数中从域中复制对象,然后在服务的整个生命周期中使用它。任何需要回写Realm对象的方法都需要在该方法中实例化自己的Realm实例。

2 个答案:

答案 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
}