By Subham Aggarwal | 7/19/2017 | General |Intermediate

Intro to Realm Android DB Solution

Intro to Realm Android DB Solution

Since the early days of Android, Android app developers were comfortable using SQLite to store their app’s 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 in nearly every app.

 

Despite all of SQLite’s advantages though, there were times when we wished we had alternatives to a relational model: because that is what we use in our Java code, the models or the POJOs.

 

There are many advantages we get with Realm, a database platform with a distinct architecture, which has emerged as a new alternative to SQLite. This lesson presents some of the main reasons why Realm has caught so much attention and why we need to consider trying it. It discusses some of the key advantages that Realm provides to Android developers over SQLite.

 

SQLite: it works, but it is not what we need usually

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 our 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 the schema in terms of contract classes
  2. Define the create/drop table commands in strings
  3. Extend SQLiteOpenHelper to run create commands and manage upgrades/downgrades

Once this is done, we’ll be ready to read and write to our database. However, we will need to convert back and forth between the objects in our application and values in the database. Simply put, it’s a lot of boilerplate code!

 

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

 

Despite its downsides, there are cases where using raw SQL is a good option. One instance is when we 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

To save us from handling raw SQL, ORMs come 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 POJOs directly.

 

Among other advantages, 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.

 

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

 

Now let’s have a look at a use-case.

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

 

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

 

The consequence is a performance loss, leading us 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 main difference between Realm and ORMs is that Realm is not an abstraction built on top of SQLite, but rather an entirely new database engine. Instead of a relational model, it’s based on an object store and its core consists of a self-contained C++ library. It currently supports Android, iOS(Objective-C and Swift), Xamarin, and React Native.

 

Realm was originally launched in June of 2014, making it about  three and a half years old—still pretty fresh technology.

 

While server database technologies have been 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 major motivators in creating something new from scratch. Furthermore, as we will see, some of Realm’s features required fundamental changes to the way a database behaves at the low level, and that just wasn’t possible building something on top of SQLite.

 

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

Easy modeling

Let us have a look at a Realm based model:

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;
}

The 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 we just need to annotate “special” fields (e.g., @PrimaryKey for our 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 we 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 sample, the Contact class contains an Address field which 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 sample. One-to-many and many-to-many relationships can be modeled with this approach.

 

This is easy to see as a relationship, as it sounds just like composition for 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.

 

There is no support for model inheritance. An easy workaround is to use composition. So if, for instance, we 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 we are into using inheritance, this is definitely something we 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 force this restriction, like DBFlow.

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 instance, we retrieve a realm object using AsyncTask’s doInBackground(), which runs in a background thread, we 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 we will need to handle the generation of these ourselves.
  • 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.
By Subham Aggarwal | 7/19/2017 | General

{{CommentsModel.TotalCount}} Comments

Your Comment

{{CommentsModel.Message}}

Recent Stories

Top DiscoverSDK Experts

User photo
3355
Ashton Torrence
Web and Windows developer
GUI | Web and 11 more
View Profile
User photo
3220
Mendy Bennett
Experienced with Ad network & Ad servers.
Mobile | Ad Networks and 1 more
View Profile
User photo
3060
Karen Fitzgerald
7 years in Cross-Platform development.
Mobile | Cross Platform Frameworks
View Profile
Show All
X

Compare Products

Select up to three two products to compare by clicking on the compare icon () of each product.

{{compareToolModel.Error}}

Now comparing:

{{product.ProductName | createSubstring:25}} X
Compare Now