Realm.io – A New Generation Of Mobile Storage

Realm.io – A New Generation Of Mobile Storage

7575099Often times mobile apps are used to display content. We want our apps to start up fast and bring us to the content as soon as possible. Therefore we store data locally for fast retrieval and offline caching. Popular solutions for such a local store is SQLite on Android or Core Data (SQLite) on iOS. Lately a new player has emerged in the mobile database scene: Realm.

Realm is a free object orientated database with opensource bindings for iOS and Android. It obeys the ACID principals with a strong focus on ease of use. The internal storage engine “TightDB” is currently closed source but will be open sourced soon.

So why should you be excited about Realm? In one word: Speed! One of the major drawbacks of existing solutions is the execution speed when doing reads. Realm is faster by a magnitude of up to 10x. So fast in fact that you can do most read and write operations on the main thread. No more crazy multitasking scenarios or lagging apps when dealing with your data.

benchmarks-android.003

This article will give you an idea how to work with the Java bindings for Realm. We will explore how to perform read/write operations, and discuss additional features and shortcomings.

Interacting with a realm

To interact with Realm you use the Realm class. A realm object is associated with the current thread it has been obtained on. That means you can only read and write to that realm on the same thread. Running from a different thread? Instantiate a new realm on that thread. To persist an object in Realm you need to extend a RealmObject:

<pre lang="java">
class Person extends RealmObject {
  private String name;
  private RealmList<Shirt> shirts;

  public String getName() { return name;}
  public void setName( String name ) { this.name = name; }
  public RealmList<Shirt> getShirts() { return shirts; }
  public void setShirts(RealmList<Shirt> shirts) { this.shirts = shirts; }
}

class Shirt extends RealmObject {
  private int color;

  public int getColor() { return color; }
  public void setColor(int color) { this.color = color; }
}
</pre>

We define a Person class that has a list of Shirts and each shirt can have a different color. In order to let Realm perform its magic, we need to provide the getters and setters which are instrumented by Realm during compile time. To create a new person with a shirt we will use the realm object:

<pre lang="java">
Realm realm = Realm.getInstance( context );
realm.beginTransaction();
Person person = realm.createObject( Person.class );
person.setName( "Peter" );
Shirt shirt = realm.createObject( Shirt.class );
shirt.setColor( 0xffff0000 );
person.getShirts().add( shirt );
realm.commitTransaction();
</pre>

Notice how we wrap the creation of the person and shirt into a transaction. The whole operation is only persisted when executing the commit successfully. Also of note: The list of shirts on the person always exists. You can safely read and write to it.

So now that we have persons in the database it is time to retrieve them. Again using the realm object:

<pre lang="java">
Person peter = realm.allObjects( Person.class )
                    .where()
                    .equalTo( "name", "Peter" )
                    .findFirst();
</pre>

Queries are performed with a fluent interface. To perform queries we reference field names. The query language offers quite a few conditions and operators like count, min, max, sum etc. You can also perform subqueries like:

<pre lang="java">
RealmResults<Person> persons = realm.allObjects( Person.class )
                                    .where()
                                    .equalTo( "shirt.color", 0xffff0000 )
                                    .findAll();
</pre>

This query gives us all people with a red shirt. Notice that the RealmResult is an Iterable so you can start working with data right away.

One interesting thing about the RealmObject is that they act as mere proxies to the concrete data in the backing store. This means that a query does not retrieve the data directly and is therefore relatively cheap. Only when the getter of an object is called, does the data get retrieved. Since the object is only a proxy we also get a live view onto our data: When adding more shirts to the peter person object, the peter.getShirts() call would instantly reflect the new state.

Remember how we spoke about a Realm belonging to the thread in which it was instantiated? A RealmObject is also tied to this thread and any write transaction is performed synchronously. You are therefore guaranteed to always have a consistent view on your data.

Limitations

So while there is a lot to like about Realm, there are a few limitations to it. One is that you have to inherit from the RealmObject. You also have to provide the getters and setters and you can not access the private data fields directly. You can also not have any other method on the RealmObject besides the getter and setter. You can however have additional fields (e.g. public static final) but they would need to be marked with @Ignore.

Regarding supported types for your fields you can use the regular Java primitives, byte[], String, Date, RealmObject and RealmList but you can not use Enum (yet).

A Realm also allows you to add a listener to it so that you get notified whenever something in the realm changes. While that is great, the listener does not tell you what has changed.

While Realm supports a sufficient set of query conditions, it is not possible to do subqueries like “get me all red shirts from peter”. You can only retrieve the top level object “peter”.

Realm does not play nicely with frameworks that use object types to figure out how to handle a certain instance. For example gson can not be used for automatic JSON serialization because realm replaces the original classes with realm proxy classes which Gson doesn’t know about.

Speaking of JSON… Realm offers the ability to directly write JSON into a realm. While deserializing into Realm is possible, there is no revers “toJson” of a RealmObject. In addition it is not possible to deserialize a JSON object directly into another realm object (effectively creating a sub-object). For example adding a green shirt from JSON directly to the peter person is not possible.

Conclusions

Now that we know how Realm works, how we can use it, and what some of its limitations are, we come to a closing thought. In the scope of a mobile app the set of Realm features is very promising. The compact query language, the always up to date data, and the speed of read operations are very compelling. I highly recommend to read through the documentation and give it a try. And don’t forget to provide feedback in the comments of this post. For the realm!

2 Comments
  • Calebe Aires
    Posted at 13:02, 2015-03-09

    Will it be on future tabris.js?