room database android poster

Easy Steps To Setup Room Database In Android

Room Database is a part of the Android Architecture components which provides an abstraction layer over SQLite which allows for more robust database access while still providing the full power of SQLite.

Room is a persistence library, part of the Android Jetpack Library

Before getting started, check out another post on the jetpack,

Getting started with WorkManager [Example]

Dependency injection on Android with Hilt[Example]

MVVM With Retrofit and Recyclerview in Kotlin [Example]

DataStore – Jetpack alternative for SharedPreference

Why use Room Database?

  • Compile-time verification of SQL queries. each @Query and @Entity is checked at the compile time.
  • Using Annotations to reduce the boilerplate code.
  • Easily integrated with other Architecture components like LiveData, and RxJava.

What is the difference between the room and the SQLite database?

  • 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.
  • As your schema changes, you need to update the affected SQL queries manually. Room solves this problem.
  • 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.
  • Room is built to work with LiveData and RxJava for data observation, while SQLite does not.

Room architecture looks like the following:

Android Room architecture

There Are Basically 3 Major Components In Room.

1. @Entity

Entity Representation of table and columns become very easy. you have to annotate @Entity to a class and the name of the class becomes the table name and, data members become the name of the columns. The @Entity class represents an entity in a table.

 @Entity(tableName = "user")
data class Users(@PrimaryKey(autoGenerate = true)var userId: Int? = null,val userName: String, var location: String, val email: String)

2. @Dao — Data Access Object

An Interface where we put all our SQL queries. We don’t require to write whole queries now; we need to make a method and annotate with specific annotations like

@Insert_— Used to insert a record into the Room database._

@Delete — Used to delete records from the Room database.

@Update — Used to update records in Room Database.

@Query— Used to enter the Query like (SELECT * FROM)

@Dao
    interface UserDao {

        @Insert
        fun insertUser(users: Users)

        @Query("Select * from user")
        fun gelAllUsers(): List<Users>

        @Update
        fun updateUser(users: Users)

        @Delete
        fun deleteUser(users: Users)

    }

3. @Database

This is an abstract class that extends RoomDatabase, this is where you define the entities (tables)and the version number of your database. It contains the database holder and serves as the main access point for the underlying connection.

@Database(entities = [Users::class], version = 1, exportSchema = false)
    @TypeConverters(Converters::class)
    abstract class AppDatabase : RoomDatabase() {

        abstract fun userDao() : UserDao
    }

Done with an explanation. Let’s start with the implementation part.


Let’s create a sample app for user management using the room database in kotlin. In the app, I have added functionalities to insert, delete, update and list all the users.

Step 1 — Add dependencies

First, We need to add dependencies for the room database in our build.gradle file.

Step 2: Create a Model Class

The room creates a table for each class annotated with @Entity.

  • Annotate the class with @Entity and use the tableName property to set the name of the table.
  • Set the primary key by adding the @primaryKey annotation to the correct fields — in our case, this is the ID of the User.
  • Set the name of the columns for the class fields using the @ColumnInfo(name = “column_name”) annotation. Feel free to skip this step if your fields already have the correct column name.
  • If multiple constructors are suitable, add the @Ignore annotation to tell Room which should be used and which not.
@Entity(tableName = "user")
    data class Users(@PrimaryKey(autoGenerate = true)var userId: Int? = null,val userName: String, var location: String, val email: String)

Step 3 — Create DAO (Data Access Objects)

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

@Dao
    interface UserDao {

        @Insert
        fun insertUser(users: Users)

        @Query("Select * from user")
        fun gelAllUsers(): List<Users>

        @Update
        fun updateUser(users: Users)

        @Delete
        fun deleteUser(users: Users)

    }

Here we just define basic SQL database functionality like inserting and deleting entries. You can see that the @Query annotation is used to annotate functions that are using queries.

You can also use parameters in your queries using: parametername.

Type Converters

Type Converters are used when we declare a property that Room and SQL don’t know how to serialize. Let’s see an example of how to serialize the List<String> data type.

class Converters {

        @TypeConverter
        fun fromString(value: String): List<String> {
            val listType = object : TypeToken<List<String>>() {

            }.type
            return Gson().fromJson(value, listType)
        }

        @TypeConverter
        fun fromArrayList(list: List<String>): String {
            val gson = Gson()
            return gson.toJson(list)
        }
    }

Step 4 — Create the database

Now, Everything is ready to create a Database. We can create a Room Database by extending the RoomDatabase.

AppDatabase.kt

@Database(entities = [Users::class], version = 1, exportSchema = false)
    @TypeConverters(Converters::class)
    abstract class AppDatabase : RoomDatabase() {

        abstract fun userDao() : UserDao

        companion object {
            private var INSTANCE: AppDatabase? = null

            fun getInstance(context: Context): AppDatabase? {
                if (INSTANCE == null) {
                    synchronized(AppDatabase::class) {
                        INSTANCE = Room.databaseBuilder(context.applicationContext,
                            AppDatabase::class.java, "user.db").allowMainThreadQueries()
                            .build()
                    }
                }
                return INSTANCE
            }

            fun destroyInstance() {
                INSTANCE = null
            }
        }
    }

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.

Step 5 — CRUD operation on Room Database

Now the room database is ready for the CRUD operation.

UserRepository.kt

class UserRepository(context: Context) {

        var db: UserDao = AppDatabase.getInstance(context)?.userDao()!!

        //Fetch All the Users
        fun getAllUsers(): List<Users> {
            return db.gelAllUsers()
        }

        // Insert new user
        fun insertUser(users: Users) {
            insertAsyncTask(db).execute(users)
        }

        // update user
        fun updateUser(users: Users) {
            db.updateUser(users)
        }

        // Delete user
        fun deleteUser(users: Users) {
            db.deleteUser(users)
        }

        private class insertAsyncTask internal constructor(private val usersDao: UserDao) :
            AsyncTask<Users, Void, Void>() {

            override fun doInBackground(vararg params: Users): Void? {
                usersDao.insertUser(params[0])
                return null
            }
        }
    }

If you try running the above code with the created database above, your app will crash as the operation performed is on the main thread. By default, Room keeps a check of that and doesn’t allow operations on the main thread as it can make your UI Not respond.

You can avoid that by using AsyncTask or Handler or Rxjava with IO schedulers or any other options which put the operation on any other thread.

There is one more option, which allows you to do the operation on the main thread. You can use the same for testing but should avoid it. To do that you can add allowMainThreadQueries() on the builder.

Also, You can download the example on Github.

Android-Example/RoomAndroidExample at master · velmurugan-murugesan/Android-Example (github.com)

Conclusion

Thanks for reading. Please try the room database in android with different queries to practice. And let me know your feedback in the comments.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *


Latest Posts