Using Room Database | Android Jetpack in Android Apps
By: Krupa Desai
Tags: Android, Android Architecture, Android Jetpack, Room, AndroidDev

Android Jetpack is a collection of Android software components to make it easier for you to develop great Android apps.

They will help you to

Follow best practices

Free you from writing boilerplate code.

Simplify complex tasks, so you can focus on the code you care about.

Now let’s talk about Room

The Room persistence library it is an abstraction layer over SQLite.

The room is an ORM (object relational mapper) for SQLite database in Android. It is part of the Architecture Components released by Google.

Room is now considered as a better approach for data persistence than SQLiteDatabase. It makes it easier to work with SQLiteDatabase objects in your app, decreasing the amount of boilerplate code and verifying SQL queries at compile time.

Why use Room?

Compile-time verification of SQL queries. each @Query and @Entity is checked at the compile time, that preserves your app from crash issues at runtime and not only it checks the only syntax, but also missing tables.

Boilerplate code

Easily integrated with other Architecture components (like LiveData)

Room vs SQLite

Room is an ORM, Object Relational Mapping library. In other words, Room will map our database objects to Java objects. Room provides an abstraction layer over SQLite to allow fluent database access while harnessing the full power of SQLite.

Difference between SQLite and Room persistence library:-

In the case of SQLite, There is no compile-time verification of raw SQLite queries. But in Room, there is SQL validation at compile time.

You need to use lots of boilerplate code to convert between SQL queries and Java data objects. But, Room maps our database objects to Java Object without boilerplate code.

As your schema changes, you need to update the affected SQL queries manually. Room solves this problem.

Room is built to work with LiveData and RxJava for data observation, while SQLite does not.

Components of Room DB:

Room has three main components of Room DB :

Entity

Dao

Database

Entity:

Represents a table within the database.Room creates a table for each class that has @Entity annotation, the fields in the class correspond to columns in the table. Therefore, the entity classes tend to be small model classes that don’t contain any logic.

Entities annotations

Before we get started with modeling our entities, we need to know some useful annotations and their attributes.

@Entity — every model class with this annotation will have a mapping table in DB

foreignKeys — names of foreign keys

indices — list of indicates on the table

primaryKeys — names of entity primary keys

tableName

@PrimaryKey — as its name indicates, this annotation points the primary key of the entity. autoGenerate — if set to true, then SQLite will be generating a unique id for the column

@PrimaryKey(autoGenerate = true)

@ColumnInfo — allows specifying custom information about column

@ColumnInfo(name = “column_name”)

@Ignore — field will not be persisted by Room

@Embeded — nested fields can be referenced directly in the SQL queries.

2. Dao

DAOs are responsible for defining the methods that access the database. In the initial SQLite, we use the Cursor objects. With Room, we don’t need all the Cursor related code and can simply define our queries using annotations in the Dao class.

3. Database

Contains the database holder and serves as the main access point for the underlying connection to your app’s persisted, relational data.

To create a database we need to define an abstract class that extends RoomDatabase . This class is annotated with @Database , lists the entities contained in the database, and the DAOs which access them.

The class that’s annotated with @Database should satisfy the following conditions:

Be an abstract class that extends RoomDatabase .

. Include the list of entities associated with the database within the annotation.

Contain an abstract method that has 0 arguments and returns the class that is annotated with @Dao .

At runtime, you can acquire an instance of Database by calling Room.databaseBuilder() or Room.inMemoryDatabaseBuilder() .

Alright! So far so good!! Let’s implement it with an example.

Step 1: Create a new project in Android Studio with empty activity.

Step 2: Add dependencies

allprojects {repositories {jcenter()maven { url ‘https://maven.google.com' }}}

And then add below dependencies to app/build.gradle file:

implementation ‘android.arch.persistence.room:runtime:1.1.1’annotationProcessor ‘android.arch.persistence.room:compiler:1.1.1’

Step 3: Create a Model Class

Now, let’s create an Entity called Person.

It is must to declare one field as primary key. You need to annotate a field with @PrimaryKey with attribute autoGenerate by default it is false

The class is annotated with @Entity and name of the table.

@Entity(tableName = “person”) public class Person { @PrimaryKey(autoGenerate = true) private int id; @ColumnInfo(name = “name”) String name; @ColumnInfo(name = “email”) String email; @ColumnInfo(name = “age”) private int age; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }

Step 4: Create Data Access Objects (DAOs)

DAOs are responsible for defining the methods that access the database.

To create a DAO we need to create an interface and annotated with @Dao.

- There are four annotations @Query, @Insert, @Update, @Delete to perform CRUD operations. @Query annotation is used to perform read operation on the database.

@Dao public interface PersonDao { @Query(“SELECT * FROM person”) List<Person> getAll(); @Query(“SELECT * FROM person where name LIKE :firstName “) Person findByName(String firstName); @Query(“SELECT COUNT(*) from person”) int countUsers(); @Insert void insertAll(Person… users); @Delete void delete(Person user); }

Step 5: Create the database

To create a database we need to define an abstract class that extends RoomDatabase . This class is annotated with @Database , lists the entities contained in the database, and the DAOs which access them.

@Database(entities = {Person.class},version = 1) public abstract class AppDatabase extends RoomDatabase{ private static AppDatabase INSTANCE; public abstract PersonDao personDao(); public static AppDatabase getAppDatabase(Context context) { if (INSTANCE == null) { INSTANCE = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, “person-database”) // allow queries on the main thread. // Don’t do this on a real app! See PersistenceBasicSample for an example. // .allowMainThreadQueries() .build(); } return INSTANCE; } public static void destroyInstance() { INSTANCE = null; } }

Step 6: Managing Data

To manage the data, first of all, we need to create an instance of the database.

then we can insert delete and update the database.

Make sure all the operation should execute on a different thread.

public class GetDataAsyc { private static final String TAG = GetDataAsyc.class.getName(); public static void populateAsync(@NonNull final AppDatabase db) { PopulateDbAsync task = new PopulateDbAsync(db); task.execute(); } public static void populateSync(@NonNull final AppDatabase db) { populateWithTestData(db); } private static Person addUser(final AppDatabase db, Person user) { db.personDao().insertAll(user); return user; } private static void populateWithTestData(AppDatabase db) { Person user = new Person(); user.setName(“Jekson1”); user.setEmail(“jek1@test.com”); user.setAge(28); addUser(db, user); List<Person> userList = db.personDao().getAll(); Log.d(GetDataAsyc.TAG, “Rows Count: “ + db.personDao().countUsers()); Log.d(GetDataAsyc.TAG, “Rows Count Name: “ + db.personDao().findByName(“Jekson”).getName()); for (int i = 0; i < userList.size(); i++) { Log.d(GetDataAsyc.TAG, “Rows Name: “ + userList.get(i).getName()); } } private static class PopulateDbAsync extends AsyncTask<Void, Void, Void> { private final AppDatabase mDb; PopulateDbAsync(AppDatabase db) { mDb = db; } @Override protected Void doInBackground(final Void… params) { populateWithTestData(mDb); return null; } } }

Step 7: Finally you get your code run using Activity as

public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); GetDataAsyc.populateAsync(AppDatabase.getAppDatabase(this));

That it for Room. I hope you liked that post.

Happy learning! Stay home, stay safe.