angryITguy
angryITguy

Reputation: 9551

What is the best practice to chain realm queries in Android?

So, I have an Android app that uses realm.io. I have to run queries asynchronously like this :

public static void getProductsByCategoryId(Realm realm, 
     String categoryId,
     OrderedRealmCollectionChangeListener<RealmResults<Product>> callback) {

    RealmResults<Product> result = realm.where(Product.class)
            .equalTo(CATEGORY, categoryId)
            .findAllAsync();
    result.addChangeListener(callback);
}

The callback will process this response, but then I need to run another query in sequence. So, you'll have queryA => process response => queryB => process response. So, the callback may have code like this

.....
getProductsByCategoryId(app.getRealmInstance(), "ABC123", firstCallback);
.....
private OrderedRealmCollectionChangeListener<RealmResults<Product>> firstCallback = new OrderedRealmCollectionChangeListener<RealmResults<Product>>() {

        @Override
        public void onChange(RealmResults<Product> realmProducts, OrderedCollectionChangeSet changeSet) {

                mProdList.addAll(mRealm.copyFromRealm(realmProducts));

                // get more product info (2nd call)
                MainApplication.getMoreProductInfo(mRealm, mCatId, false, secondCallback);
        }
    };

Currently, my understanding is that you would run queryB in the callback of queryA ? Looking at the requirements for the app, I will end up with chains of 3 or 4 queries. Is this an appropriate approach, or is there a specific pattern I should be using ? I haven't found any guidance yet in the Realm documentation.

Upvotes: 1

Views: 681

Answers (2)

EpicPandaForce
EpicPandaForce

Reputation: 81539

It's generally an indication of bad schema design if you need to do multiple queries in order to retrieve your result set, because the way Realm works is that if you can define your query results with one query (and you don't use realm.copyFromRealm() which you generally don't need to use anyways), then its elements and the results itself are all lazy-loaded.

If you cannot accomplish that, then even then, generally you probably shouldn't chain find*Async calls, because any RealmResults that you don't store as a field variable has a chance of being consumed by GC, and its change listener won't be called when isLoaded() is true (because said RealmResults no longer exists).

So what you really seem to want to do is just execute multiple queries on a background thread then return copied results to the main thread, in which case it'd just look like this

Executor executor = Executors.newSingleThreadedPool(); // or some other pool
Handler handler = new Handler(Looper.getMainLooper());

public void getQueryResults(DataLoadedCallback callback) {
    executor.execute(() -> {
        try(Realm realm = Realm.getDefaultInstance()) {
            realm.refresh(); // <-- might not be necessary
            RealmResults<XYZ> results1 = realm.where(XYZ.class)./*...*/.findAll();
            RealmResults<ZXY> results2 = realm.where(ZXY.class)./*...*/.findAll();
            RealmResults<YZX> results3 = realm.where(YZX.class)./*...*/.findAll();
            List<Something> someList = new LinkedList<>(); 
            for/*do magic transform things*/
                someList.add(blah /* blah is not a managed RealmObject */);
            }
            handler.post(() -> {
                callback.onDataLoaded(Collections.unmodifiableList(new ArrayList<>(someList)));
            });
        }
    });
}

Upvotes: 1

Christian Melchior
Christian Melchior

Reputation: 20126

Chaining queries in the callbacks are fine and "should just work", but it would be far more efficient if you can express what you want is as few queries as possible.

Ideally, we should have a query language that is powerful enough to express everything you want in one query. We are not fully there yet, but we would be very interested to hear more about what specific requirements you have.

Also, it isn't clear why you are using copyFromRealm in the method you posted, but in an ideal situation that shouldn't be necessary.

Upvotes: 0

Related Questions