Search code examples
androidrealmandroid-4.4-kitkatsamsung-mobile

Realm Query returning null inside asynctask in kitkat device


In my app running a complex algorithm based on realm results and showing the result in an expandable listview. Since the algorithm is a bit heavy I decided to do it in Asynctask and show results in listview onPostExecute. Realm cannot be accessed across thread so I opened and closed my own localRealm instance. I have checked this code and everything happening smoothly in lollipop,kitkat,jellybean devices.But in a specific kitkat device query result returning null.Since everything worked perfectly in lollipop device so I am finding it more difficult to understand why it is not doing same in that device. My code below and I am calling this from Asynctask doInBackground method.

Realm localRealm = Realm.getInstance(RealmUtility.getRealmConfig(mContext));
try {
     TotalTransaction totalTransaction = localRealm.where(TotalTransaction.class).equalTo("pk", totalTransactionPk).findFirst(); // returning null so doesn't enter inside if block
 if (totalTransaction != null && totalTransaction.isLoaded()) {
  // run algorithm and other related works based on realm results
 } catch (Exception e) {
  e.printStackTrace();
 } finally {
  if (localRealm != null) localRealm.close();
 }

and my gradle config :

compileSdkVersion 23
    buildToolsVersion '23.0.3'
    defaultConfig {
        applicationId 'com.***.***'
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 5
        versionName '1.1.5'
        multiDexEnabled true
    }

Also I am aware about realm new findAllAsync and findFirstAsync method but my query result is rather short and using inside asynctask due to heavy calculation based on the query result.

realm version: 1.1.0 android studio: 2.1.2 java : 1.7

Testing device:

  • Lollipop: Samsung J1 Nxt, Samsung J2, Samsung S6, Sony Z3
  • Kitkat: Samsung Note2, Symphony Xplorer W69Q
  • Jellybean: Walton primo
  • Problematic Kitkat device: Samsung Ace Nxt (FYI everything else other than this query in the app running properly though all other queries are in main thread)

Solution

  • You're most likely running into a race condition in how when you're starting the algorithm on the background thread and opening the instance of Realm, the data isn't committed yet on the other thread.

    To force the Realm instance to be on the latest version, you could try executing the algorithm in a transaction. Please note that transactions are blocking, so while the algorithm is running, other threads will wait until it is finished before starting their own transactions.

    Realm localRealm = Realm.getInstance(RealmUtility.getRealmConfig(mContext));
    try {
         localRealm.executeTransaction(new Realm.Transaction() {
             @Override
             public void execute(Realm localRealm) {
                 TotalTransaction totalTransaction = localRealm.where(TotalTransaction.class).equalTo("pk", totalTransactionPk).findFirst(); // returning null so doesn't enter inside if block
                 if (totalTransaction != null && totalTransaction.isLoaded()) {
                    //...
                 }
             }
         });
    

    With that, executeTransaction() will be forced to wait until the data is inserted (because transactions are blocking), and the transaction will read the latest version of data, forcing the Realm to see the TotalTransaction you're looking for.