No Soy Beto No Soy Beto - 3 months ago 62
Android Question

Realm in an Android Background Service

I am using Realm in my android application.I am receiving a notification from google drive via CompletionEvent so I need to modify my realm database in a service.

The exception I get is:

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


I have set my default configuration in my Application class the next way:

RealmConfiguration realmConfiguration = new RealmConfiguration.Builder(getApplicationContext())
.deleteRealmIfMigrationNeeded()
.build();
Realm.setDefaultConfiguration(realmConfiguration);


And in the onCreate from my service I am getting my Realm instance like this:

mRealm = Realm.getDefaultInstance();


And then I use this realm instance in the service:

mRealm.executeTransaction(realm -> {
DocumentFileRealm documentFileRealm = realm.where(DocumentFileRealm.class)
.equalTo("id", documentFileId)
.findFirst();
documentFileRealm.setDriveId(driveId);
});


But when executing this last one the app launches the IllegalStateException. I don't know why. I am not sure if it has something to do with the way I have declared the service in my android manifest so I leave it here:

<service android:name=".package.UploadCompletionService" android:exported="true">
<intent-filter>
<action android:name="com.google.android.gms.drive.events.HANDLE_EVENT"/>
</intent-filter>
</service>


Is it possible calling Realm from a background service? What is wrong with the way I am using this?

Thanks in advance.

Answer

In an IntentService, you're supposed to treat the onHandleIntent method like the doInBackground method of an AsyncTask.

So it runs on the background thread and you should make sure you close the Realm in a finally block.

public class PollingService extends IntentService {
    @Override
    public void onHandleIntent(Intent intent) {
        Realm realm = null;
        try {
            realm = Realm.getDefaultInstance();
            // go do some network calls/etc and get some data 
            realm.executeTransaction(new Realm.Transaction() {
                @Override
                public void execute(Realm realm) {
                     realm.createAllFromJson(Customer.class, customerApi.getCustomers()); // Save a bunch of new Customer objects
                }
            });
        } finally {
            if(realm != null) {
                realm.close();
            }
        }
    }
    // ...
}

onCreate runs on the UI thread, so your initialization of the Realm happens on a different thread, which is a no-go.

Comments