Pages

Friday, 26 April 2019

Quickstart: Room Persistence Library, Google's abstraction on SQLite

Contents

  1. What is Room Persistence Library?
  2. Why should I use Room?
  3. A quick and simple Room demo performing CRUD SQLite operations.
  4. Testing your Room database.

What is Room Persistence Library?

Room persistence library is a new way to build SQLite databases by directly mapping Data Model classes with their corresponding tables in the database. The Room library builds and maintains the schema of the database and tables, while also providing several safeguards and checks against errors.

Room persistence library is bundled with the Android Architecture Components called Jetpack.

Why should I use Room?

The old way of writing SQLite databases in Android was full of boilerplate code and verbose instructions, which had a high potential for errors and mistakes. Room automates this by building the required SQL queries, boilerplate codes and verifications from annotated classes.



Even the official SQLite documentation for Android recommends using Room over SQLite;
Caution: Although these APIs are powerful, they are fairly low-level and require a great deal of time and effort to use:
  • There is no compile-time verification of raw SQL queries. As your data graph changes, you need to update the affected SQL queries manually. This process can be time consuming and error prone.
  • You need to use lots of boilerplate code to convert between SQL queries and data objects.
For these reasons, we highly recommended using the Room Persistence Library as an abstraction layer for accessing information in your app's SQLite databases.

 A quick Room demo


Components of a Room Database


Let's quickly build a Room database in Android to get you acquainted with it. We take a data model called Tasks. Data classes are called Entities (Entity for singular) in Room's jargon.

I've used AndroidX support library's Room package for this project. The Room Persistence Library is under rapid improvements and updates. Beware of version changes. See the Release Notes before building your app. Always use stable versions in your production app instead of alpha (Canary), beta or rc (Release Candidate) versions. Read this informative blog here about version codes.

The following codes were built and successfully tested using these version dependencies:
//ROOM SQLite Dependencies

implementation "androidx.room:room-runtime:2.0.0"
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
annotationProcessor "androidx.room:room-compiler:2.0.0"
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
annotationProcessor "androidx.lifecycle:lifecycle-compiler:2.0.0"

Entity - The data class which will be turned into a table. It is denoted by @Entity annotation and has all the database required parameters annotated into it, like tableName, @PrimaryKey, @ColumnInfo containing table appropriate field/column name etc.

Dao - Data access objects, are interfaces for accessing the database information and return them as objects. Dao, contains the CRUD instructions annotated as @Insert, @Query or @RawQuery, @Update and @Delete. These annotated instructions are converted into proper SQL queries for SQLite by Room library on behalf of the developer. All of the instructions except for @RawQuery is checked at compile time and can identify errors early on.

Database - @Databse is an annotated abstract class which builds the database in SQLite for the android app by combining together the several entities and daos. This abstract class can also contain migration instructions to handle changes in the database, attributes etc for version changes.

Note: Room enforces multithreaded database access in order to free the UI thread (the main thread) of the app. This helps in ensuring no UI blocking occurs in your app and the user can exit your app or cancel an action easily on UI thread, rather than wait for the app to respond after the database query.

Finally, we'll make the database multithreaded control classes which will be responsible for performing an operation via Dao using asynchronous tasks. More about, AsyncTask can be found here.

InitTasksAsync - An AsyncTask class which is used to initialize the database by adding a data set.
FetchTasksAsync - An AsyncTask class which fetches all tasks currently saved in the database.
DeleteTasksAsync - This AsyncTask class deletes all tasks saved in the database.
AddAllTasksAsync - AsyncTask class to add all tasks passed in a list to the database.

One last Pro Tip - Room builds an easy to read schema in JSON format when you build a Room database. You must save this JSON schema file in your Project directory and check it into your version control with your repository as it will be useful to compare changes in the database in future revisions as well as give a quick and easy reference documentation for your Room database. Set up your app's build.gradle to save the JSON Room Schema as follows;

javaCompileOptions {
    annotationProcessorOptions {
        arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
    }
}

Testing your Room database


Now, that you've set up your Room database, you should always write a test to confirm everything is working fine with your Room database. You should write the test even before you go on ahead to compile and run your app. This will ensure that your database functions exactly the way you want it to and all SQL query and instructions give you the response you intended it to.

The test for your Room database does not require the async tasks and is tested directly using the Dao you've coded.

I'm using the latest test suite introduced by Google, called AndroidX Test. You can read more about AndroidX, the latest support library, here and the AndroidX Test package here. You can use the AndroidX Test package without needing to migrate to AndroidX. These are the dependencies which have been tested with the above Room implementation;

//Androidx Test Core Library
androidTestImplementation 'androidx.test:core:1.1.0'

//AndroidJUnitRunner and JUnit Rules
androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test:rules:1.1.1'
testImplementation 'junit:junit:4.12'

//Assertions
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
androidTestImplementation 'androidx.test.ext:truth:1.1.0'
androidTestImplementation 'com.google.truth:truth:0.42'

Now, we write our test for Room database and call it TaskDaoTests.

We can finally run our TaskDaoTests by either selecting the test in the run drop-down menu from Android Studio's top menu bar or right-clicking the test file in our navigation pane/project explorer and selecting run. This is our output if our queries behaved the way they were supposed to;




No comments:

Post a Comment

Back to Top