Search code examples
androidrealmrx-java

Realm Count incorrect/inconsistant off Main Thread


I'm seeing a very weird problem with getting the count from a query not running on the main thread. I have a UI that uses the RecyclerView adapter for Realm, and it works just dandy.

I have a method that counts the number of records before a query so it can set a starting point, for some reason it will return the previous count was before the last transaction. Here is a somewhat shortened version with the output of the log:

D/SearchController: Query Count (Main Thread): 50
D/SearchController: Query Count (Rx Thread): 50
D/SearchController: Query Count (Main Thread): 100
D/SearchController: Query Count (Rx Thread): 50

public Single<Update> searchWithCriteriaForMore(SearchCriteria searchCriteria) {
        Realm realmI = Realm.getDefaultInstance();
        Timber.d("Query Count (Main Thread): %d", realmI.where(Ad.class).equalTo("searchId", searchCriteria.id()).count());
        realmI.close();
        return Single.defer(() -> {
            Realm realm = Realm.getDefaultInstance();
            Timber.d("Query Count (Rx Thread): %d", realm.where(Ad.class).equalTo("searchId", searchCriteria.id()).count());
            realm.close();
// Stuff to add records on Rx Thread
        });
    }

The call looks like this:

SearchController.instance().searchWithCriteriaForMore(searchCriteria)
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new SingleSubscriber<SearchController.Update>() {
        ...
     }

Thoughts anyone? I've been trying to nail this down for a few weeks, thought it was something I was doing, but if I do the count on the main thread and pass it in, it works fine.

I'm running RxJava 1.2.7, RxAndroid 1.2.1, and Realm 3.3.1.


Solution

  • It feels that you have a Realm instance on RxThread somewhere which is not closed before. Since RxThread doesn't have a looper, the realm instance cannot be auto-updated. So it was locked at the version when it was created.

    Realm is using ref counter internally, the getDefaultInstance() will just return the same instance you opened on the RxThread before.

    The solution: 1. Find out which Realm instance was retrieved on the RxThread and close it properly. So the next time getDefaultInstance() will return a new Realm instance at the latest version data. 2. If it is intended to have a Realm instance on the RxThread, you can call realm.refresh() to manually move it to the latest data version.