Android – An Overview of Room Persistent Library

Hello Readers, CoolMonkTechie heartily welcomes you in this article (An Overview of Room Persistent Library).

In this article, we will learn about Android Room Persistent Library Overview. We will try to understand the basics of Room, how to use it, major components in Room and type converters in Room.

For better understanding about Android Room Persistent Library, we will discuss the below points:

  • What is Room in Android ?
  • What are the advantages of Room in Android Application ?
  • How to use it in our Project or Application?
  • What is major components of Room in Android ?
  • Type Converters in Room

A famous quote about learning is :

He who learns but does not think, is lost! He who thinks but does not learn is in great danger.

So, Let’s start.

What is Room in Android ?

Room is an Android persistence library, which is part of Google’s Android Jetpack project.

According to the Android Documentation, “Room provides an abstraction layer over SQLite to allow fluent database access while harnessing the full power of SQLite.

The library helps us create a cache of our app’s data on a device that’s running our app. This cache, which serves as our app’s single source of truth, allows users to view a consistent copy of key information within our app, regardless of whether users have an internet connection.

It means that Apps that handle significant amounts of structured data can benefit from persisting that data locally. The most common use case is to cache relevant pieces of data. That way, when the device cannot access the network, the user can still browse that content while they are offline. Any user-initiated content changes are then synced to the server after the device is back online.

What is the advantages of Room in Android Application ?

There are multiple advantages of using Room as compared to other alternate solutions like SQLiteOpenHelper:

  • Compile-time verification of queries.
  • Reduces boilerplate code.
  • Easy to understand and use.
  • Easy integration with RxJava, LiveData and Kotlin Coroutines.

How to use it in our Project or Application?

To use Room in your app, add the following dependencies to our app’s build.gradle file:

dependencies {
  def room_version = "2.2.5"

  implementation "androidx.room:room-runtime:$room_version"
  annotationProcessor "androidx.room:room-compiler:$room_version" // For Kotlin use kapt instead of annotationProcessor

  // optional - Kotlin Extensions and Coroutines support for Room
  implementation "androidx.room:room-ktx:$room_version"

  // optional - RxJava support for Room
  implementation "androidx.room:room-rxjava2:$room_version"

  // optional - Guava support for Room, including Optional and ListenableFuture
  implementation "androidx.room:room-guava:$room_version"

  // Test helpers
  testImplementation "androidx.room:room-testing:$room_version"
}

Note: For Kotlin-based apps, make sure we use kapt instead of annotationProcessor. We should also add the kotlin-kapt plugin.

What is major components of Room in Android ?

There are 3 major components in Room:

  • Database: Contains the database holder and serves as the main access point for the underlying connection to our app’s persisted, relational data.
  • Entity: Represents a table within the database.
  • DAO: Contains the methods used for accessing the database.

Our application uses the Room database to get the data access objects, or DAOs, associated with our database. The app then uses each DAO to get entities from the database and save any changes to those entities back to the database. Finally, the app uses an entity to get and set values that correspond to table columns within the database.

This relationship among the different components of Room appears in Figure 1:

1. Database

As mentioned earlier, it contains the database holder and serves as the main access point for the underlying connection to our app’s persisted, relational data. 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().

@Database(entities = arrayOf(User::class), version = 1)
abstract class UserDatabase : RoomDatabase() {
  abstract fun userDao(): UserDao
}

To get an instance of the database, you can use the following method:

val db = Room.databaseBuilder(
    applicationContext,
    UserDatabase::class.java, "users-db"
    ).build()

We have noted that :

  • If our app runs in a single process, we should follow the singleton design pattern when instantiating an AppDatabase object. Each RoomDatabase instance is fairly expensive, and we rarely need access to multiple instances within a single process.
  • If our app runs in multiple processes, include enableMultiInstanceInvalidation() in our database builder invocation. That way, when we have an instance of AppDatabase in each process, we can invalidate the shared database file in one process, and this invalidation automatically propagates to the instances of AppDatabase within other processes.”

2. Entity

An Entity represents a table within a database. This class is annotated with @Entity annotation. Data members in these class represent the columns within a table. For example :

@Entity
data class User(
  @PrimaryKey val uid: Int,
  @ColumnInfo(name = "first_name") val firstName: String?,
  @ColumnInfo(name = "last_name") val lastName: String?
)
  • All the fields in an entity must either be public or have getter & setter methods.
  • Entity class should have an empty constructor (if all fields are accessible) or a parametrised constructor which takes all the fields. Room can also use partial constructors.
  • Each entity class must have at least one primary key. We can use either @PrimaryKey annotation to define single field primary key or primaryKeys attribute of @Entity annotation for multiple fields. We can also use autoGenerate property of @PrimaryKey annotation to automatically assign primary keys.
@Entity(primaryKeys = arrayOf("firstName", "lastName"))
  • By default, Room uses the class name as the database table name. If we want the table to have a unique name, set the tableName property of the @Entity annotation. Similarly, we can use the name property of the @ColumnInfo annotation for defining the name of columns.
@Entity(tableName = "users")
  • If we don’t want to persist in any field, we can annotate them using @Ignore.
@Ignore val picture: Bitmap?
  • We can use the indices property of @Entity annotation to add indices to an entity. Also, we can create unique indices by setting the unique property of an @Index annotation to true.
@Entity(indices = arrayOf(Index(value = ["last_name", "address"])))@Entity(indices = arrayOf(Index(value = ["first_name", "last_name"],
        unique = true)))

3. Data Access Object (DAO)

DAOs provide an API for accessing the database. This is an interface which is annotated with @Dao annotation. All the methods in this interface are used for getting data from the database or changing the database. These methods are annotated with annotations like @Query, @Insert, @Delete.

@Dao
interface UserDao {
  @Query("SELECT * FROM user")
  fun getAll(): List<User>
  
  @Query("SELECT * FROM user WHERE uid IN (:userIds)")
  fun loadAllByIds(userIds: IntArray): List<User>
  
  @Insert
  fun insertAll(vararg users: User)
  
  @Delete
  fun delete(user: User)
}

Here, all queries using UserDao are made on the caller thread. So we should take care that no method is invoked from the UI(main) thread.

Type Converters in Room

Sometimes, we might need to persist a custom data type in a single database column. We can use type converters for these types of use cases.

class Converters {
  @TypeConverter
  fun fromTimestamp(value: Long?): Date? {
  return value?.let { Date(it) }
  }

  @TypeConverter
  fun dateToTimestamp(date: Date?): Long? {
  return date?.time?.toLong()
  }
}

Next, we have to add the @TypeConverters annotation to the RoomDatabase class so that Room can use the converter, we’ve defined for each entity and DAO in that RoomDatabase.

@Database(entities = arrayOf(User::class), version = 1)
@TypeConverters(Converters::class)
abstract class UserDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
}

So Room takes care of these concerns for us, we highly recommend using Room instead of SQLite.

That’s all about in this article.

Conclusion

In this article, we understood about Android Room Persistent Library Overview like Basic, advantages, How to use it, major components and custom type converters in Room.

Thanks for reading! I hope you enjoyed and learned about the basic of Android Room Persistent Library. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find Other articles of CoolmonkTechie as below link :

You can also follow official website and tutorials of Android as below links :

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING !!???

Exit mobile version