Choices, choices, choices. When it comes to storing data, Android developers have a plethora of available libraries. Whether it's hanging on to a couple of objects, or building a massive collection, the tools are at our disposal, waiting to get used. Some of them come out of the box, like shared preferences and pure SQL, others require external dependencies. Thankfully, I’m not here to talk about writing long illegible queries, I promise. Instead, I will be comparing the big-league players: The newly announced Room Persistence Library, the age-old Realm, and the lesser known ObjectBox, which recently came out of beta. The final choice, I leave to you, however by the end it should be (more or less) clear which one comes on top. However, before we get to the clash of the titans, let’s introduce them first.

Ever since it’s conception (around 2011, originally as “TightDB”) Realm has been the go-to choice for many developers. Why, you ask? Simplicity (uses almost standard Java objects), speed (written mostly in C++) and SQL (none of it). Without going into too much detail, creating a Realm database is simple, using it — even more so. The library needs minimal setup and the official documentation does a good job of holding your hand through the process.

A model for the object to store is the first thing that’s needed:



var size: Long = 0,

var name: String = "",

var tempReference: Int = 0) : RealmObject() {} open class Box ( @PrimaryKey var size: Long = 0,var name: String = "", @Ignore var tempReference: Int = 0) : RealmObject() {}

The only thing here worth noting is that if you use Kotlin, all of your variables must have default values. The annotations and the necessary inheritance of RealmObject are (hopefully) self-explanatory, so let’s move on.

Using Realm is as simple as this:

Realm.init(context)

val realm = Realm.getDefaultInstance() val box = realm.where(Box::class.java).findFirst()

realm.executeTransaction {

//modifying an exsiting object

box.size = 20

box.name = "John" //creating a new object

val secondBox = realm.createObject(Box::class.java)

secondBox.size = 30

}

Full example

Note: With this being a database centered guide, I will leave the multithreading to you.

Note 2: Yes, the box’s name is John.

Room Persistence Library 🔗

Enter Room! The newest and shiniest of Google’s libraries. Taking a center place in their official architecture guidelines, Room provides an abstraction layer over SQLite to allow fluent database access while harnessing the full power of SQLite. It does a pretty good job of tucking away the SQL and exposing clean, understandable Java methods to the developer. So, remember when I promised no queries? Well now we’re going to write some queries! But don’t worry, Room includes some safety features, which alert you in case of nasty mistakes.

Since, at the time of writing this article (and probably long after that), Room is the popular kid in town, I’ll keep its introduction as short as I can.

There are 3 major components in Room, all represented as annotations:

Database: You can use this component to create a database holder. The annotation defines the list of entities, and the class’s contents- the list of data access objects (DAOs) in the database. It is also the access point for the underlying connection.

The annotated class should be an abstract class that extends RoomDatabase. You can acquire an instance of it by calling Room.databaseBuilder() or Room.inMemoryDatabaseBuilder() .

Entity: This component represents a class that holds a database row. For each entity, a database table is created to hold the items. You must reference the entity class through the entities array in the Database class.

DAO: This component represents a class or interface as a Data Access Object. DAOs are responsible for defining the methods that access the database. The class that is annotated with @Database must contain an abstract method that has 0 arguments and returns the class that is annotated with @Dao.

The following are 3 implementations (shamelessly copied from this excellent article) of the above-mentioned components:

@Entity(tableName = “task”)

data class Task(@ColumnInfo(name = “completed_flag”) var completed: Boolean = false,

@ColumnInfo(name = “task_desciption”) var description: String) {

@ColumnInfo(name = “id”)

@PrimaryKey(autoGenerate = true) var id: Long = 0

} @Dao interface TaskDao {

@Query(“select * from task”)

fun getAllTasks(): List<Task> @Query(“select * from task where id = :p0”)

fun findTaskById(id: Long): Task @Insert(onConflict = REPLACE)

fun insertTask(task: Task) @Delete

fun deleteTask(task: Task)

} @Database(entities = arrayOf(Task::class), version = 1, exportSchema = false)

abstract class AppDatabase : RoomDatabase() { abstract fun taskDao(): TaskDao

}

Creating a database and calling its methods is as simple as this:

var database = Room.databaseBuilder(context, AppDatabase::class.java,”db”).allowMainThreadQueries().build()

database.taskDao().insertTask( Task(description = “simple!”) )

Being the newest of the bunch, ObjectBox brings a lot to the table. But with the bar set this high already, can this new NoSQL technology compare to the veterans in the field? Surely it must pack quite the punch, if it’s to go head-to-head with Realm and Room. And indeed, it packs not one, but a whole series of punches. Here are some of the top highlights of the newcomers:

Speed: Just like Realm, ObjectBox offers excellent performance, sometimes even surpassing its competitors (more on that later).

QueryBuilder: With ObjectBox you simply query for objects with checks at compile time.

Object Relations: Object references / relationships are a built-in type; they are native references.

No manual schema migrations: It takes care of new object versions with added, removed and renamed properties.

Et cetera, et cetera.

So how does it look like in practice?

The must-have model should look familiar by now:

@Entity

data class Note (



val text: String

) data class Note ( @Id var id: Long = 0,val text: String

ObjectBox works with objects called Boxes (go figure) to store and work with data. Only 2 lines divide you from working with the database:

The “Box Store” object which, preferably, should reside in your Application class:

MyObjectBox.builder().androidContext(App.this).build()

And individual “Boxes” for each of the models that you have in your database. These boxes will serve as an interaction point between you and the database.

var notesBox = boxStore.boxFor(Note::class.java)

An important detail is that these Box types are automatically generated, meaning less things to worry about!

Once you have this down, you are ready to go, and these are some of the available methods for you to use:

notesBox.put(note)

notesBox.remove(note)

notesBox.count()

For a complete list of methods available in the Box class, check its JavaDoc. A thing to note here is the so-called DaoCompat compatibility layer which allows for greenDAO like API for ObjectBox.

The Comparison

So far, all libraries have done more or less the same thing, some with, some without the use of SQL. However, it’s their differences that interest us. In the images that follow, I’ve tested the performance of each of the 3 approaches, using this open-source benchmarking app.