5

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 .

Karunesh Palekar
  • 2,190
  • 1
  • 9
  • 18

1 Answers1

9

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

yousef
  • 1,345
  • 1
  • 12
  • 20
  • hi sir! just tried it out but my callback never fires...I guess I am missing something. Is it enough having this above code or should I tell Dagger to use the module in the viewModel? – riccardogabellone Jul 16 '22 at 11:34
  • @riccardogabellone above code on application scope – yousef Jul 30 '22 at 11:55