RealmList<RealmString> is an anti-pattern!

Gabor Varadi
HackerNoon.com
4 min readJan 16, 2017

--

EDIT: Any Realm version from 4.0.0-RC1 and above supports RealmList<String> natively, so use that instead.

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

I’ll be honest: I really dislike titles that say, “X is an anti-pattern”. Especially when the pitfalls of a specific approach aren’t obvious, the opposite is also claimed to be an anti-pattern, and so on.

In the case of RealmList<RealmString>, you can’t really “support” it at all. I even should have mentioned this already in my Realm schema design article. The idea of using RealmList<RealmString> to overcome the limitation that RealmList of primitives is not supported (WHICH IS NOT A LIMITATION SINCE 4.0.0) was designed as a hack, back when there was no better solution. Apart from being hideous and not exactly transient to the developer, it also brings some problems along with it.

Well, there is a just as hacky solution, but at least you don’t bloat your Realm schema with it :)

Problems of RealmList<RealmString>

1.) You need to define a new RealmObject for it

You need to create a RealmObject for something that isn’t really meant to be a separate class, an unnecessary wrapper. It also creates a link, which means…

2.) Objects accessed via a link need to be deleted manually

Basically if you use RealmList<RealmString> in a class, then in order to clear up the RealmString objects bound to it, you must iterate the RealmResults first, call deleteAllFromRealm() on their managed RealmList, and only then can you actually delete the objects. Iterating a RealmResults creates a proxy per accessed object, so this can be memory-intensive with large datasets, even though this data should belong directly to the RealmObject, not via a link.

3.) Link queries are slower than normal queries

Simply put, a link query takes more time than a query on an indexed field.

4.) Any write to the RealmString table notifies any other RealmObject that has a link to it (pre-3.0)

(only applies before Realm 3.0) The coarse-grained change listeners assume that your object could have been modified if RealmString was modified, which results in unnecessary calls to RealmChangeListener, which typically calls adapter.notifyDataSetChanged().

Solution: storing RealmList<primitive> as a String

Yup, the problem is that people try to store the primitives as a List. It doesn’t have to be a List, though. Think about it — you can parcel any List of elements into a String. Even your every-day JSON parser does it all the time.

Parcelling a list to a String is especially easy with a list of primitive values.

Look at this gist from the RealmList<RealmInteger>, … issue:

Instead of creating an unnecessary wrapper for the List<String>, instead it maps it into a single String field, with join separators. For Java, this can be done with Commons-Lang’s StringUtils.join(), or Stream API backports. Or manually with StringBuilder. Whichever works.

Why does this work well?

Since Realm 0.88.0, you need to add Realm to the project as a Gradle plugin, right? Well with that came in the Realm-Transformer, which converts all direct field access into proxy method calls.

This is great, because this is what allows us to manually create “computed properties” like total as this.total = quantity * price;.

But this allows us to create custom getters/setters, that set the String field even though you give it a List, or returns a List even though the field is a String.

Something like this:

And if we don’t want to add Commons-Lang to the project, you can use this method from Spring Framework:

Or something of that sort. Joining a string shouldn’t be too hard.

Conclusion

Don’t create unnecessary links. Purge the RealmList<RealmString>.

Added note (2017–01–17):

But if you still need to separate the elements into their own list, then create a separate RealmObject for it, not a RealmString. Here is a concrete example:

This way, you retain a bidirectional link, your TelephoneNumber is independently queryable and sortable, allows queries such as find the telephone numbers that contains “___", and then use telephoneNumber.getPerson() to get whom it belongs to.

Hacker Noon is how hackers start their afternoons. We’re a part of the @AMI family. We are now accepting submissions and happy to discuss advertising & sponsorship opportunities.

If you enjoyed this story, we recommend reading our latest tech stories and trending tech stories. Until next time, don’t take the realities of the world for granted!

--

--

Gabor Varadi
HackerNoon.com

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