Search code examples
androidrealm

Realm onSuccessListener is called after long delay


In my application I use realm on a background thread just for write transactions and on the UI thread for querying from the same file. At first I used manual transaction on background thread and noticed that notification about change arrived to the UI thread after very long time.

The DB is not very big (<1MB) and with few thousand objects at most. In the problematic transaction i iterate over a lot of objects but change values in just few of them (~4 object instances have some primitive values changed). Usually duration between beginTransaction to log after commitTransaction is around 100ms, however notification to the UI thread arrives 1-20s later (the delay seems random to me, changes in each transaction are nearly the same but delay changes..).

I tried to call realm.refresh() on UI thread after commitTransaction on the background thread was done. It kinda helped, delay was shorter but visual hang for a few seconds was terrible of course. For test i changed the implementation to executeTransactionAsync with onSuccess callback, behavior is the same, onSuccess is called long seconds after the transaction block is finished.

I tried simple profiling, background thread was fully used during the delay but not by any work i scheduled to it, it seems that realm is using it.

So my question is what is realm doing after commitTransaction() until publishing notifications? What may cause such a long time to make minor changes to DB? Are there some best practices to keep it fast? Can there be a bottleneck caused by more open realmInstances on the UI thread (each fragment has one open for queries + notification listener, more fragments are on the screen at the same time)?

//edit: Data is nearly tree shaped. At the root are few instances of class A, it has few primitive attributes and RealmList (list length <1000). class B has around 30 primitive attributes (including Strings) and RealmList (length <5). Class C has around 40 primitive attributes (including Strings) and a few RealmLists and some pointers to other RealmClasses. In the transaction in question, i need to change single instance of C.

//Solved by updating my schema to use backlinks on all bidirectional relations, now it is fast. From 5s to 200ms.


Solution

  • Generally since Realm-Java 3.0.0, the recommendations for schema design changed a bit.

    Previously if you wanted to access parent from child, and child from parent, you would need to have a schema like this:

    class A extends RealmObject {
        private RealmList<B> children;
    
    class B extends RealmObject {
        private RealmList<A> parents;
    

    But since Realm 3.5.0 (aka when queries across backlinks were introduced), the recommendation is this:

    class A extends RealmObject {
        private RealmList<B> children;
    
    class B extends RealmObject {
        @LinkingObjects("children")
        private final RealmResults<A> parents = null;
    

    Because bi-directional links can cause the Object-Store's diffing to run for an unusually large amount of time.

    Without seeing your schema, I'd say this is your best bet.