Using Room with Hilt

Using Room DB with Hilt

Saurabh Vashisht

--

Hilt is the new dependency Injection tool in town. It supports injection in android classes out of the box. In this article we will see how to use Room with Hilt.
Let’s talk a bit about what we are doing then we can get around to the how.

We have a Fragment (MyChannelsFragment) that has a view model (MyChannelsViewModel). The fragment shows data present in view model.
The view model gets the data from a repository (MyChannelRepository). The repository needs to access data from local storage. In this article we will inject a DAO object in our repository that allows it to access local storage.
We have already completed the first 2 stages of injection in the previous article. These 2 steps are :

  1. Injecting view model in fragment.
  2. Injecting repository in view model.

For these steps you can check out this previous article :

At this point I am assuming you know how to setup Hilt and have an idea of what the role of a repository should be. If you are not clear about any of these then check out the above article.

Now we need to inject an instance of our DAO (Data access object) in Repository. If you wish to carry along this article you can check out the starting code here

First step is adding the dependencies

dependencies{
...
implementation "androidx.room:room-runtime:2.3.0"
kapt "androidx.room:room-compiler:2.3.0"

}

Add compiler options

android {
...
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
arguments += [
"room.schemaLocation":"$projectDir/schemas".toString(),
"room.incremental":"true",
"room.expandProjection":"true"]
}
}
}
}

Now open the object class that will be stored in local database and add the annotation @Entity on top of it.

@Entity
data class Channel(@PrimaryKey(autoGenerate = true) val id: Int)

Here Channel is the name of object we wish to store in our local database. This will create a table for this object with a similar schema. @PrimaryKey(autoGenerate = true) marks id as the primary key for this table and it will be auto generated when a new row is added to this table.

Now let’s create a DAO class for our Channel entity

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import java.nio.channels.Channels

@Dao
interface ChannelDao {

@Query("SELECT * FROM channel")
fun getAllChannels(): List<Channels>

@Insert
fun insertChannel(channel: Channel)
}

Now we need to create a Database class

import androidx.room.Database
import androidx.room.RoomDatabase

@Database(entities = [Channel::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun channelDao(): ChannelDao
}

Our database setup is now complete. Next step is to add it’s dependency to our repository.

class ChannelRepositoryImpl @Inject constructor(private val channelDao : ChannelDao) {
...
}

Now we need to tell Hilt how to provide an instance of ChannelDao. To achieve this create a new class DatabaseModule.

import dagger.Module
import dagger.Provides
@InstallIn(SingletonComponent::class)
@Module
class DatabaseModule {
@Provides
fun provideChannelDao(appDatabase: AppDatabase): ChannelDao {
return appDatabase.channelDao()
}
}

Let’s examine this class in detail.

@InstallIn(SingletonComponent::class)

This annotation tells Hilt that the dependencies provided via this module shall stay alive as long as application is running.

@Module

This annotation tells Hilt that this class contributes to dependency injection object graph.

@Provides

This annotation marks the method provideChannelDao as a provider of ChannelDao.

Now Hilt knows how to create an instance of ChannelDao but to create such an instance, Hilt needs to know how to create an instance of AppDatabase. For that add another method below provideChannelDao.

@Provides
@Singleton
fun provideAppDatabase(@ApplicationContext appContext: Context): AppDatabase {
return Room.databaseBuilder(
appContext,
AppDatabase::class.java,
"RssReader"
).build()
}

There are two things to note here.

  1. @Singleton annotation tells Hilt that AppDatabase should be initialized only once. And the same instance should be provided every time it’s needed to be injected.
  2. @ApplicationContext allows hilt to provide application context without having to explicitly specify how to obtain it.

That’s it. Now you can start using your DAO in repository to access local storage.

You can checkout the final code for this article here

--

--