Mobile11 minute read

Realm Is the Best Android Database Solution

Since the inception of the platform, Android developers have had pretty much only one option for a database: SQLite. Although feature-rich and powerful, it wasn’t quite what Android app developers needed. Realm, a modern, efficient database solution for mobile platforms, turned out to be an amazing replacement for SQLite on Android.

In this article, Toptal Software Engineer Mateus Gondim Romão Batista explains why you should use Realm for your next Android application.


Toptalauthors are vetted experts in their fields and write on topics in which they have demonstrated experience. All of our content is peer reviewed and validated by Toptal experts in the same field.

Since the inception of the platform, Android developers have had pretty much only one option for a database: SQLite. Although feature-rich and powerful, it wasn’t quite what Android app developers needed. Realm, a modern, efficient database solution for mobile platforms, turned out to be an amazing replacement for SQLite on Android.

In this article, Toptal Software Engineer Mateus Gondim Romão Batista explains why you should use Realm for your next Android application.


Toptalauthors are vetted experts in their fields and write on topics in which they have demonstrated experience. All of our content is peer reviewed and validated by Toptal experts in the same field.
Mateus Gondim Romão Batista
Verified Expert in Engineering
12 Years of Experience

With nearly a decade of Java experience, Mateus (BCompSc) has done web projects using Python, Django, and JS, lately focusing on Android.

Expertise

Share

Since Android was created, we app developers have been using SQLite to store our local data. Sometimes directly with SQL statements, sometimes using an Object-Relational Mapper (ORM) as an abstraction layer, but either way, we’ve been using SQLite at the end of the day.

Despite all of SQLite’s advantages, though, there were times when we wished we had alternatives to a relational model: Something that could spare us from having to add boilerplate code to convert values to and from the database, or enable us to skip setting up mappings between classes and tables, fields and columns, foreign keys, etc.

In other words, a database with data structures more similar to the ones we actually use at the application level. Better yet, if it could be memory efficient by design, allowing for better experiences in resources constrained devices, that would be awesome.

These are, in fact, some of the out-of-the-box benefits we get with Realm, a database platform with a distinct architecture, which has emerged as a new alternative to SQLite.

This article presents some of the main reasons why Realm has caught so much attention and why you might want to consider trying it. It discusses some of the key advantages that Realm provides to Android developers over SQLite.

Since Realm is available on multiple platforms, some of what will be covered in this article has relevance to other mobile platforms as well, such as iOS, Xamarin, and React Native.

SQLite: It Works, but It is Not What You Need Most of the Time

Most mobile developers are probably familiar with SQLite. It has been around since 2000, and it is arguably the most used relational database engine in the world.

SQLite has a number of benefits we all acknowledge, one of which is its native support on Android.

The fact that it is a standard SQL relational database also minimizes the learning curve for those who come from a relational database background. It also provides reasonably good performance if used to its full potential (leveraging features, such as prepared statements, bulk operations with transactions, etc). Although SQLite may not scale very well for all of your needs.

Dealing directly with SQL statements has a number of downsides, though.

According to the official Android documentation, here are the steps needed to start reading/writing to SQLite:

  1. Describe your schema in terms of contract classes.
  2. Define your create/drop table commands in strings.
  3. Extend SQLiteOpenHelper to run create commands and manage upgrades/downgrades.

Once you’ve done this, you’ll be ready to read and write to your database. However, you will need to convert back and forth between the objects in your application and values in the database. Long story short: It’s a lot of boilerplate code!

Another issue is maintainability. As your project grows larger and the need to write more complex queries arises, you will end up with big chunks of raw SQL queries in strings. If later on you need to change the logic of those queries, it can be quite a hassle.

Despite its downsides, there are cases where using raw SQL is your best option. One example is when you are developing a library where performance and size are critical factors and adding a third-party library should be avoided if possible.

Object-Relational Mapper: The Band-aid For SQL Challenges

To save us from dealing with raw SQL, ORMs came to the rescue.

Some of the most famous Android ORMs are DBFlow, greenDAO, and OrmLite.

The greatest value they bring is SQLite abstraction, letting us map database entities to Java objects relatively easy.

Among other benefits, application developers get to work with objects, a much more familiar data structure. It also helps with maintainability, as we are now handling high-level objects with a stronger typing and leaving the dirty work to the libraries. Less struggling with building queries by concatenating strings or manually handling the connection with the database. Fewer typos.

Although it’s a fact that these ORMs have raised the bar on Android databases, they also have their drawbacks. In many cases, you end up loading unnecessary data.

Here is an example.

Say you have a table with 15 columns, and in a certain screen of your app, a list of objects from this table is displayed. This list displays values from only three columns. Therefore, by loading all data from the table row, you end up bringing five times more data than you actually needed for that screen.

Truth be told, in some of these libraries you can specify which columns you want to retrieve upfront, but for that you need to add further code, and even so, that will not be enough in case you can only know exactly which columns you will use after you look at the data itself: some data might be unnecessarily loaded anyway.

Additionally, there are often scenarios where you have complex queries to make, and your ORM library just doesn’t offer you a way to describe these queries with its API. That can make you write inefficient queries that do more calculation than what you need, for example.

The consequence is a performance loss, leading you to resort to raw SQL. While this is not a deal breaker for many of us, it hurts the main purpose of the object-relational mapping and takes us back to some of the aforementioned issues regarding SQLite.

Realm: A Perfect Alternative

Realm Mobile Database is a database designed for mobile devices from the ground up.

The key difference between Realm and ORMs is that Realm is not an abstraction built on top of SQLite, but a whole new database engine. Rather than a relational model, it is based on an object store. Its core consists of a self-contained C++ library. It currently supports Android, iOS(Objective-C and Swift), Xamarin, and React Native.

Realm was launched in June 2014, so it is currently two and a half years old (pretty new!).

While server database technologies were going through a revolution since 2007, with many new ones emerging, the database technology for mobile devices remained stuck with SQLite and its wrappers. This was one of the key motivations to create something from scratch. Furthermore, as we will see, some of Realm’s features required fundamental changes to the way a database behaves at a low level, and that was just not possible building something on top of SQLite.

But is Realm really worth it? Here are the top reasons why you should consider adding Realm to your tool belt.

Easy modeling

Here’s an example of some models created with Realm:

public class Contact extends RealmObject {
    @PrimaryKey
    String id;
    protected String name;
    String email;
    @Ignore
    public int sessionId;

    //Relationships
    private Address address;
    private RealmList<Contact> friends;

    //getters & setter left out for brevity
}
public class Address extends RealmObject {
    @PrimaryKey
    public Long id;

    public String name;
    public String address;
    public String city;
    public String state;
    public long phone;
}

Your models extend from RealmObject. Realm accepts all primitive types and its boxed types (except for char), String, Date and byte[]. It also supports subclasses of RealmObject and RealmList<? extends RealmObject> to model relationships.

Fields can have any access level (private, public, protected, etc). All fields are persisted by default, and you just need to annotate “special” fields (e.g., @PrimaryKey for your primary key field, @Ignore to set non-persisted fields, etc.).

The interesting thing about this approach is that it keeps classes less “annotation polluted” in comparison to ORMs, as in most of them you need annotations to map classes to tables, regular fields to database columns, foreign key fields to other tables, and so on.

Relationships

When it comes to relationships, there are two options:

  • Add a model as the field from another model. In our example, the Contact class contains an Address field and that defines their relationship. A contact might have an address, but nothing stops this same address from being added to other contacts. That allows for one-to-one and one-to-many-relationships.

  • Add a RealmList of the models being referenced. RealmLists behave quite like good old Java Lists, acting as a container of Realm objects. We can see that our Contact model has a RealmList of contacts, which are her friends in this example. One-to-many and many-to-many relationships can be modeled with this approach.

I like this way of representing relationships because it feels very natural to us Java developers. By adding these objects (or lists of these objects) directly as fields of our class, just like we would do for other non-model classes, we don’t need to deal with SQLite settings for foreign keys.

Caveat: There is no support for model inheritance. The current workaround is to use composition. So if, for example, you have an Animal model and were hoping to create a Dog model extending from Animal, you will instead have to add an Animal instance as a field in Dog. There is a big debate on Composition vs. Inheritance. If you are into using inheritance, this is definitely something you need to know about Realm. With SQLite, this could be implemented using two tables (one for the parent and one for the child) connected by a foreign key. Some ORMs also don’t impose this restriction, like DBFlow.

Retrieve Only Data You Need! Zero-copy Design

This is a killer feature.

Realm applies the concept of zero-copy design, which means that data is never copied to memory. The results you get from a query are actually just pointers to the real data. The data itself is lazily loaded as you access it.

For example, you have a model with 10 fields (columns in SQL). If you query for objects of this model to display them listed on a screen, and you just need three out of the 10 fields to fill the list items, those will be the only fields retrieved.

As a consequence, queries are blazingly fast (see here and here for some benchmark results).

This is a big advantage over ORMs which usually load all data from selected SQL rows upfront.

Screen loading becomes vastly more efficient as a result without requiring any further effort from the developer: it’s just Realm’s default behavior.

Additionally, this also means that apps consume less memory and, considering we’re talking about a resource-constrained environment such as mobile devices, that can make a big difference.

Another consequence of the zero-copy approach is that objects managed by Realm are auto-updated.

Data is never copied to memory. If you have results from a query, and another thread has updated this data on the database after your query, the results you possess will already reflect these changes. Your results are only pointers to the actual data. So when you access values from fields, the most up-to-date data is returned.

Illustration: Acessing Realm data from multiple objects and threads.

If you have already read data from Realm objects and displayed them on the screen, for example, and want to receive updates for when the underlying data changes, you can add a listener:

final RealmResults<Contact> johns = realm.where(Contact.class).beginsWith("name", "John ").findAll();
johns.addChangeListener(new RealmChangeListener<RealmResults<Contact>>() {
      @Override
      public void onChange(RealmResults<Contact> results) {
          // UPDATE UI
      }
});

It’s Not Just a Wrapper

Although we have dozens of options for ORMs, they are wrappers, and it all comes down to SQLite underneath, which limits how far they can get. In contrast, Realm is not just another SQLite wrapper. It has the freedom to provide features that ORMs just can’t offer.

One of the fundamental changes with Realm is being able to store data as an object graph store.

This means Realm is objects all the way down, from the programming language level to the database. Consequently, there’s way less conversion being made back and forth as you write and read values, in comparison to a relational database.

Database structures reflect more closely data structures that application developers use. In fact, this is one of the major reasons why there’s a movement away from relational modeling and toward aggregate models on server-side development. Realm finally brings some of these ideas to the mobile development world.

If we think of components in Realm’s architecture, at the bottom there is its core with the most fundamental implementation of the platform. On top of it, we will have binding libraries to each supported platform.

Illustration: Realm architecture from core to various libraries.

When using a wrapper for some technology you have no control over, you eventually need to provide some sort of abstraction layer around it.

Realm binding libs are designed to be as thin as possible, to cut out abstraction complexity. They mostly propagate the design idea from Core. By having control of the whole architecture, these components work in better sync with each other.

One practical example is the access to other referenced objects (foreign keys in SQL). Realm’s file structure is based on native links, so when you query for relationships, rather than having to translate an ORM abstraction to relational and/or join multiple tables, you get raw links to the objects at a file system level in the file format.

That’s objects pointing directly to other objects. Thus, querying a relationship is the same as querying an integer column, for example. No need for expensive operations traversing foreign keys. It’s all about following pointers.

Community & Support

Realm is under active development and has been releasing updated versions pretty often.

All components from the Realm Mobile Database are open-source. They are very responsive on their issue tracker and Stack Overflow, so you can expect good and fast support on these channels.

Also, feedback from the community is taken into account when prioritizing issues (bugs, improvements, feature requests, etc.). It’s always good to know you can have a say in the development of the tools you use.

I started using Realm in 2015, and since then, I’ve bumped into several posts on the web with various opinions about Realm. We will talk about its limitations soon, but one thing I’ve noticed is that many of the complaints made at the time of the post have since been fixed.

When I got to know about Realm, for example, there was no support yet for custom methods on models and asynchronous calls. These were deal breakers for many at the time, but both are currently supported.

Such development speed and responsiveness makes us more confident that we won’t be waiting long for important features.

Limitations

As with everything in life, Realm is not all roses. Besides the inheritance limitation previously mentioned, there are other shortcomings to bear in mind:

  • Although it’s possible to have multiple threads reading from and writing to the database at the same time, Realm objects cannot be moved across threads. So if, for example, you retrieve a realm object using AsyncTask’s doInBackground(), which runs in a background thread, you cannot pass this instance to the onPostExecute() methods, since those run on the main thread. Possible workarounds for this situation would be to either make a copy of the object and pass it along or pass the object’s id and retrieve the object again on onPostExecute(). Realm offers synchronous and asynchronous methods for read/write.

  • There’s no support for auto-increment primary keys, so you will need to handle the generation of these yourself.

  • It’s not possible to access the database from distinct processes at the same time. According to their documentation, multi-process support is coming soon.

Realm Is The Future of Mobile Database Solutions

SQLite is a solid, robust, and proven database engine, and relational databases are not going away anytime soon. There are a number of good ORMs out there what will do the trick for many scenarios as well.

However, it is important to keep up-to-date on current trends.

In this regard, I think that Realm is one of the biggest upcoming trends in recent years when it comes to mobile database development.

Realm brings with it a unique approach to deal with data that’s valuable to developers, not only because it can be a better option than existing solutions, but also because it broadens our horizons in terms of new possibilities and raises the bar on mobile database technology.

Do you already have experience with Realm? Please feel free to share your thoughts.

Hire a Toptal expert on this topic.
Hire Now
Mateus Gondim Romão Batista

Mateus Gondim Romão Batista

Verified Expert in Engineering
12 Years of Experience

Recife - State of Pernambuco, Brazil

Member since September 30, 2016

About the author

With nearly a decade of Java experience, Mateus (BCompSc) has done web projects using Python, Django, and JS, lately focusing on Android.

authors are vetted experts in their fields and write on topics in which they have demonstrated experience. All of our content is peer reviewed and validated by Toptal experts in the same field.

Expertise

World-class articles, delivered weekly.

Subscription implies consent to our privacy policy

World-class articles, delivered weekly.

Subscription implies consent to our privacy policy

Join the Toptal® community.