0

I am having trouble with waiting for fresh data on a worker thread. The data object is copied to realm on a main thread, but almost immediately after that I need to access this object from a worker thread, which then reports that no such object exists in realm right now ( its newly opened realm instance ) . I remember that there was a method load() that would block execution to the point of next update, but it was removed in newer versions. And I can't use change notification for this as this is not a Looper thread..

The only way I can think of right now is to sleep the thread for some magic period of time and pray to god that it has updated already, but that approach is imho wildly indeterministic.

Can anybody advise here, how can I ensure that I read the most current data at the time ?

koperko
  • 2,447
  • 13
  • 19
  • 1
    On a worker-thread opening and closing your Realm for each unit of work should do the trick. If you see old data it is because your Realm wasn't properly closed from last time. – Christian Melchior Nov 21 '16 at 12:05
  • Yes, I think that was exactly the case .. I forgot to close the instance, which is pretty weird that I didn't run out of memory as this is a request interceptor, so instances were created very rapidly... – koperko Nov 21 '16 at 12:30

3 Answers3

1

A possible hack would be to create a transaction that you cancel at the end.

realm.beginTransaction(); // blocks while there are other transactions
... // you always see the latest version of the Realm here
realm.cancelTransaction();

This works if the thread is started after the UI thread saves the object into the Realm.

You can also try this workaround: https://stackoverflow.com/a/38839808/2413303 (although it doesn't really help with waiting)

Community
  • 1
  • 1
EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
0

try using QueryListener, which is trigger whenewer object, satisfying certain criteria is updated

Alex Shutov
  • 3,217
  • 2
  • 13
  • 11
  • How exactly can QueryListener be set up ? I can't find anything on it within the documentation or RealmQuery object methods. Is this somehow different from regular change notifications set up on RealmResults or RealmObject and if so, do they deliver on non-Looper threads ? – koperko Nov 21 '16 at 11:24
  • Listeners doesn't work on non-looper threads. If you know for sure that something has changed, you can use `realm.waitForChange()`. However your first statement indicate you don't control your events as good as you would like as if a write happened on the UI thread it would 100% be available on a background thread if that thread was started after the write on the UI thread. – Christian Melchior Nov 21 '16 at 11:29
  • @AlexShutov because I don't have control over the created threads by the library... – koperko Nov 21 '16 at 11:33
  • @ChristianMelchior that is true, the worker threads are coming from Rx library ... More specifically they are returned by an `io` scheduler, which I believe keeps a thread pool.. – koperko Nov 21 '16 at 11:36
0

using realm.beginTransaction() and realm.commitTransaction() instead of realm.executeTransaction(Realm.Transaction)

The problem with this is that executeTransaction() automatically handles calling realm.cancelTransaction() in case an exception is thrown, while the other alternative typically neglects the try-catch.

Yes, you’re supposed to call cancel on transactions that aren’t going to end up being committed.

For example, on background threads:

    // SAY NO TO THIS
Realm realm = Realm.getDefaultInstance();
realm.beginTransaction(); // NO
realm.copyToRealm(dog)
realm.commitTransaction(); // NO NO NO NO NO
    // YOU NEED TO CLOSE THE REALM

// ----------------------

// SAY YES TO THIS
Realm realm = null;
try { // I could use try-with-resources here
    realm = Realm.getDefaultInstance();
    realm.executeTransaction(new Realm.Transaction() {
        @Override
        public void execute(Realm realm) {
            realm.insertOrUpdate(dog);
        }
    });
} finally {
  if(realm != null) {
    realm.close();
  }
}

// OR IN SHORT (Retrolambda)

try(Realm realmInstance = Realm.getDefaultInstance()) {
    realmInstance.executeTransaction((realm) -> realm.insertOrUpdate(dog));
}

The problem with this is that on background threads, having an open Realm instance that you don’t close even when the thread execution is over is very costly, and can cause strange errors. As such, it’s recommended to close the Realm on your background thread when the execution is done in a finally block. This includes IntentServices.

Sifundo Moyo
  • 175
  • 1
  • 7