In this article we will dive deep into Room component. In case you missed the previous articles or don’t know about architecture components then head on to my previous article Introduction to Android Architecture Components.
The code in this article is written in Kotlin. In case you don’t know Kotlin. Read this series of article to get started.
Room is a persistence library designed to help you save your app data into the SQLite database which ships with every Android version.
Room is a robust SQL mapping library
- It provides local data persistence
- Abstraction layer over existing SQLite database
- Checks SQL query at compile time
- Ability to observe for changes in the database using LiveData
- Eliminates the boilerplate code
- Plays well with RxJava
The spectrum shows some of the persistence libraries and where they fall in between SQL and Objects. The Room library falls in between SQL and Objects that’s because you need to write SQL.
Anatomy of Room
- It defines the database holder
- It is main access point to the database connection
- It defines list of entities and database access objects (DAO)
Database Access Objects (DAO)
- They are main component of Room because they are responsible for defining methods that access database
- It defines the methods for interaction with the database
- The implementation is auto-generated at compile-time
- For each entity a database table is created
- It represents a class which holds a database row
Adding it to your project
Add the following dependencies in your app or module
compile "android.arch.persistence.room:runtime:1.0.0-rc1"// Java
annotationProcessor "android.arch.persistence.room:compiler:1.0.0-rc1"// Kotlin
PS: Release Candidate 1 (RC1) is the latest version of Architecture Components (except Paging) at the moment of writing this article.
Let’s code with Room!
The Entity class is marked with
@Entity annotation. It defines the structure of the column.
The above entity creates a table named
users with 2 columns namely
id — auto-generated primary key and
- Table name is same as class name; you can change it using
- A column is created for each field and same name that’s defined in the entity; you can change the column name using
@ColumnInfo(name = "ANYTHING")annotation.
It is required for every entity to have primary key. You can even have composite primary keys:
In order to tell Room to ignore a particular field you need to annotate it with
Since beta1 release, Room ignores
transient fields by default unless they are annotated with
PS: The table names in SQLite are case-insensitive
Database Access Objects (DAO)
The DAO is the one who talks with the database to perform CRUD operations based upon functions defined in the DAO. It can be either
abstract class as the implementation is written by Room.
I’m pretty sure it’s understandable except
@Query annotation. During the Persistence spectrum we saw Room is in between SQL and Objects because it supports SQL. Well
@Query is the place where you’ll mostly need to write SQL.
The SQL query is checked at the compile time itself so if you made a typo or the query is wrong then you’ll get a compile time error. You can even query multiple tables.
Usually we want to change the state of UI when data in the database is updated. Room allows that by providing observable queries which will notify when the data in the database is changed/updated. It is achieved using
Missed my previous article about LiveData or need to know more then check the article below:
Exploring LiveData Architecture component
LiveData is a data holder class that keeps a value and allows this value to be observed and respects the lifecycle of…
The last component is database; it brings all the pieces of Room together viz; all the entities and their DAOs.
The version indicates the schema version. It needs to be incremented when the database schema is changed/altered.
Getting the database instance:
The database instance is expensive. It is recommended to keep it in a singleton maybe by using Dagger 2
Ideally, we need to tell Room when the database version is changed and provide a guide or steps to perform migration from old version to new version.
To find out more about how to implement database migrations and how they work under the hood, check out this post:
Object Relationships are a bit tricky in Room. It’s one of the thing which needs little improvement, nonetheless let’s dive into it.
Unlike other object-relational mapping libraries, Room doesn’t allow entities directly referencing each other due to lazy loading problem. That said, it allows relations using
ForeignKey which is quite powerful but tricky.
Sometimes we would want to decompose our object into sub-fields but keep them under one logical unit.
In layman terms, let’s say
user is your entity object which has
address which contains it’s own fields like city, and you want to store it under the same table called
users because logically address belongs to a user.
Let’s look at code because we understand that better ;)
Note: There is no
@Entity on top of
Address class because we don’t want to create a separate
address table in the database. Moreover, as mentioned earlier Room doesn’t support nested entity.
This is how the table will be created in the database. The fields from
Address class will be automatically embedded by Room.
Let’s look at same example of
ForeignKey — one to one relation.
In, the user entity we mention it’s foreign key relation with the
Address entity by specifying the foreign key of
User to primary key of
We define the same
Address class only this time with
@Entity annonation which needs
The entities which we defined above will be stored in this fashion in the database.
Now the important question arises, how do I fetch the data? We need to create an extra POJO to define what we need. This is done to tackle the lazy loading issue.
We define a new POJO to fetch
user object and city name from
PS: You can define POJO to fetch other things of addresses table or all of the fields. It depends upon what you need
Finally we need to write SQL query in the DAO.
And that’s how it’s done! I know it’s slightly tricky. It gets more tricky with one to many.
I’ll be writing a series of articles soon; showcasing testing for each architecture components which includes Room.
Meanwhile, if your curious and can’t wait then you can read about testing Room database from official docs.
inMemoryDatabaseBuilder()while developing/prototyping or testing your application. It clears the database on closing the connection to the database.
fallbackToDestructiveMigrations()if you are really sure about it. The good part is you don’t need to write migrations. The bad part is data will be purged from the database every time you increment the database version.
- Use Repository pattern to sync the data between Room and Web (server).
I love the fact that Room is here to save us from the persistence problem and it supports reactive nature and all it’s goodies. I don’t like that we need to write the migration code that too in SQL. I wish it was automatic or semi-automatic; another thing is working with relation is tricky with Room which I think will get easier after v1.0.
Lastly, I’m glad that it uses SQLite database which is available on every Android device; preventing additional size indirectly helping us build slim APKs.
Room is like Retrofit for database
Update: What’s next?
In the next part we will look at RxJava, transactions Room and few more small things as pointed out by Andrei.