Room Database / Sqflite in android with kotlin

 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 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:



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 record from Room database.

@Update — Used to update record 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.


am going to 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 tableNameproperty 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 @Ignoreannotation 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.

Post a Comment

Previous Post Next Post

Subscribe Us


Get tutorials, Flutter news and other exclusive content delivered to your inbox. Join 1000+ growth-oriented Flutter developers subscribed to the newsletter

100% value, 0% spam. Unsubscribe anytime