Sneak Peek: what’s going to be new in Realm-Java 2.4.0 (or 3.0.0?)

Gabor Varadi
4 min readFeb 23, 2017

There are changes on the horizon! A new snapshot, maybe even a new major version. If you’re curious to know what’s been going on, here’s a sneak peek.

“Results” integration (#3834) was merged

In 2.4.0-SNAPSHOT, after 4 months of hard work; the internal logic behind RealmResults has finally been adapted to use the realm-object-store’s Results. But what does this mean?

  • BREAKING CHANGE: realmResults.distinct() now returns a new RealmResults, instead of distinct in place.

This was actually a bug from a long time ago (#2947), so I’m glad to see it fixed.

  • BREAKING CHANGE: RealmChangeListeners added to RealmObject are now also called when the object becomes invalidated (deleted)

This is actually a fix for #3138, which means that finally you can update your UI appropriately when the RealmObject becomes invalidated — without having a field reference RealmResults that you add a change listener to as well.

Just make sure you check realmObject.isValid() inside your RealmChangeListener.

  • BREAKING CHANGE: simple ascending for-loops in the following format no longer work inside transactions (if the modification changes the evaluated result set).
RealmResults<MyObject> realmResults = realm.where(MyObject.class)
.equalTo("f", true)
.findAll();
for(int i = 0; i < realmResults.size(); i++) {
MyObject obj = realmResults.get(i);
obj.setF(false); // modifies the RealmResults!
...

To overcome this change, you can use either iterators (preferred)

for(MyObject obj: realmResults) {    
...

or reverse iteration.

for(int i = realmResults.size()-1; i >= 0; i--) {    
MyObject obj = realmResults.get(i);
...

Wait, but why?

This is actually a compromise. Previously, updating RealmResults was delegated to the next event loop, by delaying the call to realmResults.syncIfNeeded(). This was a change introduced in 0.89.0 to provide stable iterators while inside a transaction.

But now, with the Object Store Results, the RealmResults that are obtained inside a transaction are automatically live-updated for each change (#4164).

This is because while you are executing a transaction, you’re directly creating the newest version of the Realm, and the data you see is always up to date.

So instead, to force a RealmResults to stay at a given version, it’s possible to create a “collection snapshot”.

Collection snapshots work just like the previous RealmResults behavior, which wasn’t synced to the latest version. Meaning, deleted objects inside them become invalidated, but the snapshot list itself stays the same.

RealmResults<MyObject> res = realm.where(MyObject.class)
.findAll();
OrderedRealmCollection<MyObject> snapshot = res.createSnapshot();for(int i = 0; i < snapshot.size(); i++) {
MyObject obj = snapshot.get(i);
...

Iterators are automatically executed on a snapshot of the collection, so you don’t need to create a snapshot for it manually.

for(MyObject obj: realmResults) { // uses snapshot
...

Also, as it was pointed out to me by Mulong Chen,

  • beginTransaction() could trigger the RealmResults listeners if there are changes, because beginTransaction() bumps the Realm version — but some will be suppressable (#4225) in order to support drag and drop.
  • RealmResults itself doesn’t use snapshot at all (however the iterator does).

So that’s interesting! This new behavior also fixes #3002.

— —

  • CHANGE: Local commit triggers Realm global listener and RealmObject listener on current thread immediately instead of in the next event loop.

This means that when you commit a transaction on the UI thread, then the RealmChangeListeners are immediately called for change listeners registered on Realm and RealmObject.

Technically though, if you’re not doing synchronous writes inside RealmChangeListeners, you probably won’t notice a difference :)

— —

Okay, so what’s the benefit?

Glad you asked!

RealmList.addChangeListener() will now work (#4216)

Previously, because RealmList is an actual table and not a result set, you weren’t able to listen to changes on it.

Now it’ll work.

Link sorts (#672) are now available!

Previously you were not able to do a sort like this.

RealmResults<Person> persons = realm.where(Person.class)
.findAllSorted("parent.name");

Now it works. But more importantly…

Fine-grained notifications (#4191) are merged!

With Results integration comes fine-grained notifications!

Previously, RealmChangeListener was called for every realmResults that belonged to a given table. Additionally, it was also called when a related table was modified ( RealmList<T>). Now, RealmResults are only notified when they actually change.

Additionally, using the new OrderedRealmCollectionChangeListener, it’s now possible to receive an OrderedCollectionChangeSet which contains the indices of what objects have been deleted, modified, moved or inserted.

This brings us….

RecyclerView animations! (#83)

Using this listener (source from realm-android-adapters), it’s now possible to use Realm with RecyclerView animations directly!

Conclusion

Realm-Java 2.4.0 (or 3.0.0?) is bound to bring us a few changes, along with major feature updates that people have been eagerly waiting for.

Realm intends to have a big, official blog post about it too (#4193), you’ll see when it’s out!

And if you by chance know the new Results behavior to be different than what I mentioned above, please correct me.

--

--

Gabor Varadi

Android dev. Zhuinden, or EpicPandaForce @ SO. Extension function fan #Kotlin, dislikes multiple Activities/Fragment backstack.