简体   繁体   中英

Android Realm - Accessing Realm Object from Service

I have a realm object that is created in my activity. I need to be able to access this object within a service that I created. However I'm getting the error when creating the Realm object within the service

        mRealm = Realm.getInstance(getApplicationContext());

java.lang.IllegalStateException: Realm access from incorrect thread. Realm objects can only be accessed on the thread they were created

Now I understand this means that because the realm object was created on my activity, I cannot access it from a background thread. However, I'm not finding an easy way around this other than creating my own custom Handler Thread but that just seems like a clunky way of doing it.

Am I missing something here or is there really no better way to be able to access Realm object from within different threads?

Update:

I dug a little deeper to figure out that in an IntentService, the onHandleIntent method runs in a separate thread than other methods within the class. Therefore, I cannot create a class level Realm instance and be able to interact with that inside and outside of the onHandleIntent method. That is what was causing the thread exception. Aside from creating a separate instance of Realm in each method I need to access the object and retrieving it over and over again, I think Ilya Tretyakov's answer will be best. I can copy the object from realm in my constructor and then work with it throughout the life of the service. Any methods that need to write back to the Realm object will need to instantiate their own Realm instance within that method.

You can try to use realm.copyFromRealm(youRealmObject); . These method copy Realm data into normal Java objects and detaching them from Realm.

Here is the example of usage:

youRealmObject = realm.copyFromRealm(youRealmObject);

Here is the information about it from docs:

Makes a standalone in-memory copy of an already persisted RealmObject. This is a deep copy that will copy all referenced objects. The copied object(s) are all detached from Realm so they will no longer be automatically updated. This means that the copied objects might contain data that are no longer consistent with other managed Realm objects. WARNING : Any changes to copied objects can be merged back into Realm using copyToRealmOrUpdate(RealmObject), but all fields will be overridden, not just those that were changed. This includes references to other objects, and can potentially override changes made by other threads.

https://realm.io/docs/java/latest/api/io/realm/Realm.html#copyFromRealm-E-

Technically you're supposed to open the Realm instance at the beginning of the background thread, close it at the end of execution in that background that, and pass it to methods in between.

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

Using realm.copyFromRealm() is a workaround, not a solution.


With AS 3.0, you can actually use try-with-resources no matter what your minSDK is (just like if you were using 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
} 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM