javaandroidkotlinandroid-room

Prepopulating Room Database with Hilt


I am trying to prepoluate Room database with data using RoomDatabase.Callback() method and also had success in doing so . Later I tried to work the same with Hilt , but can't figure out how to add the callback while providing the database in hilt module .

This is the DatabaseModule :

@Module
@InstallIn(ApplicationComponent::class)
object DatabaseModule {

    @Singleton
    @Provides
    fun provideDatabase(
        @ApplicationContext context: Context
    ): PersonDatabase {
        return Room.databaseBuilder(
            context,
            PersonDatabase::class.java,
            "person_database"
        ).build()

    }

    @Singleton
    @Provides
    fun provideDao(database: PersonDatabase) = database.personDao()

}

This is the Callback class :


class PersonCallback @Inject constructor(
    private val dao: PersonDao
) : RoomDatabase.Callback() {

    private val applicationScope = CoroutineScope(SupervisorJob())

    override fun onCreate(db: SupportSQLiteDatabase) {
        super.onCreate(db)
        applicationScope.launch(Dispatchers.IO) {
            populateDatabase()
        }
    }

    private suspend fun populateDatabase() {
        val person = Person("FirstName", "LastName", 20)
        dao.insertData(person)
    }
}

What I have tried is using the database and providing the dao like this , but it stucks at a loop and the app crashes out . The error in short says , that the following manner is recursive and hence not permittable


    @Singleton
    @Provides
    fun provideDatabase(
        @ApplicationContext context: Context
    ): PersonDatabase {
        return Room.databaseBuilder(
            context,
            PersonDatabase::class.java,
            "person_database"
        ).addCallback(
            PersonCallback(provideDatabase(context).personDao())
        ).build()

    }

Then , I followed an SO post and tried to replicate it , which is :

Pre-populating Room database with Hilt without creating an extra instance of the database

Following the above , the application crashed again , providing a huge error which referenced to autogenerated class and had nothing much to it to make it more meaningful

Another Method which I tried was to pass dao as an parameter , but it again crashed with an error saying it leads to a dependency cycle since I also have passed the dao to the Repository as a constructor parameter.


    @Singleton
    @Provides
    fun provideDatabase(
        @ApplicationContext context: Context,
        personDao: PersonDao
    ): PersonDatabase {
        return Room.databaseBuilder(
            context,
            PersonDatabase::class.java,
            "person_database"
        ).addCallback(
            PersonCallback(personDao)
        ).build()

    }

After all this tries , I am not able to figure out how should I pass dao to the callback class and make it work . I request to suggest some ways to make this happen or any alternatives will also be appreciated .


Solution

  • According link you add in your question you find solution just edit first method provide PersonDatabase

    @Singleton
    @Provides
    fun provideDatabase(
        @ApplicationContext context: Context,
        provider: Provider<PersonDao>
    ): PersonDatabase {
        return Room.databaseBuilder(
            context,
            PersonDatabase::class.java,
            "person_database"
        ).addCallback(
            PersonCallback(provider)
        ).build()
    
    }
    

    Then your callback Class take provider for PersonDao jus edit for your class

    class PersonCallback (
    private val provider: Provider<PersonDao>
      ) : RoomDatabase.Callback() {
    
    private val applicationScope = CoroutineScope(SupervisorJob())
    
    override fun onCreate(db: SupportSQLiteDatabase) {
        super.onCreate(db)
        applicationScope.launch(Dispatchers.IO) {
            populateDatabase()
        }
    }
    
    private suspend fun populateDatabase() {
        val person = Person("FirstName", "LastName", 20)
        provider.get().insertData(person)
    }
    }
    

    I try this code work fine with me