Some people call it “safe integration”. Some call it “clean architecture” and “complete separation of the data layer from the presentation layer”. Personally, I like to call it a “faulty abstraction”.

— — — — — — — — — — — — — — — — — — — — — — — —

Realm as a reactive data model with lazy-evaluated cursors

If you’ve read any of my previous articles, then you know by now that Realm is a NoSQL database (so, it is not SQLite), and when you define a query, then it provides you with RealmResults — which essentially functions as a lazy-evaluated cursor for each element that satisfies a given set of conditions, in the form of a list, within the given version of the Realm instance.

Querying does not read from the database. You only actually read from the database when you access a property of a specific managed proxy obtained from the results.

As the Realm instance gets updated (as a result of committed transactions from other threads), so does the “cursor” — the result set is automatically updated whenever the underlying data changes (along with all managed objects).

This is because of what Realm calls zero-copy architecture: managed proxies don’t contain data, they just allow you to access the data inside the Realm. On a given thread, for a specific version of the Realm, the view of the underlying data is always consistent.

— — — — — — — — — — — — — — — — — — — — — — — — — —

The trade-off: thread confinement

Now, in order to provide consistent results without additional synchronization, Realm’s query results (and instances and managed objects) are thread-confined. This means that they can only be accessed on the thread that created them.

This also means that to obtain a result set on the UI thread, you must query using a Realm instance that belongs to the UI thread. The Realm on the UI thread can execute the query itself on a background thread using find*Async() methods, but the final result set will read the data from the Realm on the UI thread.

(Of course, this generally isn’t an issue, this is why you add @Index on your fields you use in your conditions, right?)

— — — — — — — — — — — — — — — — — — — — — — — —

Throwing it all out the window by detaching RealmObjects and thinking you’re doing the right thing

Well, some people don’t like a reactive data model being handed to them. Consistent view of the data? Single source of truth? Reactivity, automatic updates, change listeners? Lazy evaluation, no need for manual pagination?

Who needs all of these when you can use realm.copyFromRealm() and throw it all out the window! Realm is a “database just like SQLite, so clearly it should be used exactly like SQLite”, right?

…

If you ask me, then no. If you’re trying to use Realm as if it were bare-bones SQLite, then you have a fundamental misunderstanding of what you’re trying to abstract away.

And no amounts of RxJava will suddenly make you seem less like you don’t know what you’re doing.

Creating unmanaged RealmObjects on a thread pool. What could possibly go wrong.

The initial problem…

…is dogmatically trying to keep all operations off the UI thread (as if evaluating entire data sets at once using raw SQLite), and detaching RealmObjects just to have basic lists without any reactivity.

The REAL problem…

…is that people try to create an abstraction for Realm that doesn’t cover it.

The (theoretical) solutions

1.) the abstraction of Realm’s layer

Realm provides two major things: the data layer, and the ability to observe changes of the data layer. (or as referenced, the “Data storage and observation layer”).

If we keep this in mind, then we can realize that in reality, our RealmResults isn’t just a “list”. It isn’t something you should just pass around with realm.copyFromRealm(realmResults) . It is a list we can observe and attach change listeners to: an ObservableList . And its RealmChangeListener is a ChangeListener .

So if we truly want to make our logic agnostic to Realm’s existence, we should wrap the RealmResults into an ObservableList interface that we define, and we should be able to obtain this on the UI thread (and observe it on the UI thread).

We shouldn’t just convert it into an ArrayList. That makes no sense.

2.) moving evaluation off the UI thread(?)

If we are fine with losing lazy evaluation, but would still prefer to keep notifications, then you can still figure out how to move the observable results to your own HandlerThread with its own Handler using RxAndroid’s HandlerScheduler.

After all, the reason why auto-updating works on the UI thread is not because it’s the UI thread, but because it has a Handler!

I started an experiment called Monarchy which does exactly this.

3.) accessing Realm instances without passing them to the methods

People often realize that they can’t use Realm as just another Singleton, because you need a thread-specific instance of the Realm.

What people generally don’t realize is that they can create so-called “Thread-local Singletons”.

Thread-local Realm instances

Realm actually already does this in the background, but adds reference counting to every getInstance() call — primarily to support having a single open Realm managed directly through the Activity lifecycle.

But you can easily create your own thread-local global instance for any thread, and manage this manually with openDatabase() , getDatabase() and closeDatabase() methods for your thread-specific instance.

— — — — — — — — — — — — — — — — — — — — — — — — —

Conclusion

Even if you choose “deep integration”, no one actually stops you from hiding Realm under an abstraction, using your own defined reactive collection interfaces and a repository pattern. You just have to be responsible, and understand what you’re actually trying to abstract away.

After all, you should do your best to retain Realm’s features it was designed for: lazy-evaluation, reactivity, automatic updates.

If you find yourself using realm.copyFromRealm() in your code, and it’s not because you’re either:

modifying the object in a form, and plan on saving it back with all fields modified when you press “Save”

creating a list that can be reordered, and persist back the RANK parameter based on the new order of this list

sending your RealmObject through GSON

But because you’re:

looking for a way to pass RealmObjects (or RealmResults) between threads

Then you should probably think a bit more about how you’re trying to use Realm, because currently — you’re doing it wrong. After all, there’s no sense in copying from a zero-copy database, is there?

— — — — — — — — — — — — —

Added note (2017–01–20):

But if you’re still insistent on using Realm wrong and detaching your objects, throwing away all lazy evaluation — at least please do it right (I mean “not too wrong”):