The rights of this image are for RayWenderLich

Room — Kotlin, Android Architecture Components

Marcos Sandoval
MindOrks
Published in
7 min readAug 3, 2018

--

When we talk about storing information in a persistent way on Android, the most important and “easy” option is to use plain SQLite, if you do a good implementation, this implies:

  1. Creating a contract class which contains the constants for the URIs, tables and columns name (which should extends from BaseColumns).
  2. Creating a class that extends SQLiteOpenHelper which will create the database the first time it is called. To do this, you need to manually create a query string indicating the name of the tables and columns you want to create, using the contract defined on the above step. This is difficult to maintain and can introduce a bunch of errors.
  3. Once you have created your DB, if you want to insert, update or delete information you have to instantiate your subclass of SQLiteOpenHelper , get a writable version of the DB, also you need to create a ContentValues using the contract class created on the first step, to set the keys and the values with the information you need to save. In the case of update and delete operations, you can also define a projection to select specific information base on the value of a column.
  4. In the case you want to read information, you have to instantiate your subclass of SQLiteOpenHelper, get a readable version of the DB and create a projection. As a result, you will get a Cursor which then you have to go through, column by column, to get the information you need.

It sounds like too much work, doesn’t it? If you want to do this easier, you can use an ORM but you still need to manually defined and create the DB, subclassing SQLiteOpenHelper and creating the contract classes. So, the question is: Is there any way to simplify all this process?, the answer is: Yes, Room is your solution.

What is Room?

The Room persistence library provides an abstraction layer over SQLite to allow for more robust database access while harnessing the full power of SQLite.

Room is part of the Android Architecture Components presented in the Google I/O 2016. It is not an ORM, it is a whole library that allows us to create and manipulate SQLite databases easier, by using annotations we can define our databases, its tables and operations; Room will automatically translate these annotations into SQLite instructions/queries to perform the correspondent operations into the DB engine.

Room architecture looks like follow:

Room Architecture by Google

The three major components of Room are:

  • Database: It represents the DB, it is an object that holds a connection to the SQLite DB and all the operations are executed through it. It is annotated with @Database.
  • Entity: Represents a table within the Room Database. It should be annotated with @Entity.
  • DAO: An interface that contains the methods to access the Database. It is annotated with @Dao.

Too much talk, let see an example:

Let’s imagine that we need to create an app to store your gym routine, we are going to have 4 entities in our database as we’ll show below. All the sample codes are written using kotlin, if you don’t know Kotlin or you want to learn more, I would like to invite you to visit this link and read my article about it.

The first thing we need to do is to update our gradle file. It should look like the following

App.gragle

As we mentioned, Room is composed of three major components: Entities, DAO’s and DataBase. Let’s see and analyze each of them:

Entities

For our example we are going to use four entities: Gender, Exercise, Routine and Trainee.

Gender.kt

It represents the gender of the trainee.

Things to know:

  • All the classes that represent an entity of the database have to be annotated with @Entity.
  • With the annotation @PrimaryKey(autoGenerate = true) we are indicating that id is the primary key of the entity and should be autoGenerate by the database engine.

Exercise.kt

It represents an exercise that it is part of a routine.

Things to notice:

  • By default, Room uses the field names as the column names in the database. If you want a column to have a different name, add the @ColumnInfo annotation to a field.

Routine.kt

It is basically a container of exercises that together create an exercise routine.

Things to notice:

  • When a class is annotated with @Entity the name of the tablet will be the name of the class, if we want to use a different one we have to add the tableName property along with the @Entity annotation.
  • @TypeConverters annotation has to be used when we declare a property which type is a custom class, a list, date type or any other type that Room and SQL don’t know how to serialize. In this case, we are using the annotation at the class field level whereby only that field will be able to use it. Depending on where the annotation is placed it will behave differently as explained here.

Trainee.kt

It represents the owner of the routine.

There are several things to be noticed here:

  • The indices property at @Entity annotation is used to index certain fields in the database to speed up the queries. In this case, we are indicating that the columns: nameand age have to be indexed.
  • The property called foreignKeys is used to indicate a relationship between two or more tables, it receives an array of ForeignKeys . entity property is the name of the father class, parentColumns is the name of the column at the father class and childColumns is the name of the column at the class where it is used.
  • We use @Embedded annotation when we want to represent an object that we’d like to decompose into its subfields within a table. We can, then, query the embedded fields just as you would for other individual columns. This allow us to express an entity or plain old Java object (POJO) as a cohesive whole in our database logic, even if the object contains several fields.

DAOs

Data Access Objects or DAOs are used to access our data when we implement Room. Each DAO have to include a set of methods to manipulate the data (insert, update, delete or get).

A DAO can be implemented as an interface or as an abstract class, in our case we are going to use an interface. Due to all the DAOs are basically identical we will show only one.

GenderDao.kt

Some things to notice:

  • All the DAOs have to be annotated with @Dao.
  • A function annotated with @Insert , @Update or @Deletehave to receive an instance of the desired class as a parameter, which represents the object that we want to insert, update or delete respectively.
  • In the case of insert or update operations, we can use the property onConflict to indicate what to do when a conflict performing the operation happens. The strategies available to use are: REPLACE , ABORT , FAIL , IGNORE and ROLLBACK.
  • If we want to get specific information from one or more entities we can annotate a function with @Query and provide a SQL script as parameter. Another advantage of use Room is: if the SQL query provided in the annotation is invalid, it will fail on compilation time and not in runtime.

Type Converters

As we said before, Type Converters are used when we declare a property which Room and SQL don’t know how to serialize. Let’s see an example of how to serialize datedata type.

DateTypeConverter.kt

DataBase

It represents the DB, it holds a connection to the actual SQLite DB.

AppDatabase.kt

Things to notice here:

  • This is an abstract class that has to extend from RoomDatabase.
  • It has to be annotated with @Database, it receives a list of entities with all the classes that compose the database (all these classes have to be annotated with @Entity). We also have to provide a database version.
  • We have to declare an abstract function for each of the entities included in the @Database annotation, this function has to return the correspondentDAO (A class annotated with @Dao).
  • Finally, we declare a companion object to get static access to the method getAppDataBase which gives us a singleton instance of the database.

Using the Room database

Now let’s see a very simple example of how to use the Room database we just created

MainActivity.kt

What are we doing?

  • We’re getting the instance of the database and GenderDao.
  • We’re creating two Gender instances: Male and Female.
  • We’re inserting the two instances created into de DB.
  • We’re querying the DB to get all the genders store on it.
  • We’re merging the name of all the genders we got from the DB and we’re setting the text of the TextView with that value.

And that’s it :) This is almost everything you need to know to create and use a Database on Android with Room. The whole code of the project can be gotten from here. Thanks for reading!

--

--