Search code examples
androidkotlinandroid-roomkotlin-coroutinesdagger-hilt

Coroutine scope for a RoomDatabase.Callback() in a RoomDatabase instantiated outside the ViewModel?


I am refactoring my app for DI with Hilt, and before I had a ViewModel instantiating the RoomDatabase to get the DAO and pass it to the repository. The .getDatabase method has a CoroutineScope parameter for launching a coroutine inside the .RoomDatabase.Callback() to populate the database asynchronously.

class MyViewModel(application: Application) : AndroidViewModel(application) {
    init {
        val dao = MyDB.getDatabase(
            application,
            viewModelScope   //using viewModelScope inside the ViewModel
        ).myDAO()
        repository = MyRepository(dao)
    }
}

abstract class MyDB : RoomDatabase() {

    abstract fun myDAO(): MyDAO

    private class MyDatabaseCallback(private val scope: CoroutineScope) : RoomDatabase.Callback() {
...
}

Now with Hilt the DB will be instantiated in a Module installed in the SingletonComponent:

@Module
@InstallIn(SingletonComponent::class)
object DBModule {
    @Provides
    fun provideDao(@ApplicationContext applicationContext: Context) : MyDAO {
        return MyDB.getDatabase(
            applicationContext,
            scope         // What CoroutineScope to use here ???
        ).myDAO
    }

    @Provides
    fun provideRepository(dao: MyDAO) = MyRepository(dao)
}

What's the best scope to use in this case, as viewModelScope cannot be used anymore? And how to reference it? Ideally an ActivityRetained scoped one, so it's not scoped to the entire application, but it will survive Activity restarts (i.e. configuration changes, etc)

Thank you in advance.


Solution

  • I hope It helps with your use case.

        // You will have to use hilt with viewModel as well in order to used below function further more I don't recomment to used that as
        // ViewModelScop strick inside viewModel. If It comes to database then It should not restrict to viewModel Infact database is a component which 
        // Provide service to each part of the application so use Simple Coroutine scope... 
        // Incase something goes wrong and your activity kills/destoryed then the opertaion get stoped because of viewModelScope
        @Provides
        fun provideCorountineScope(viewModel: MyViewModel): CoroutineScope {
            return viewModel.viewModelScope
        }
    
        @Singleton
        @Provides
        fun providesCoroutineScope(): CoroutineScope {
            // Run this code when providing an instance of CoroutineScope
            return CoroutineScope(SupervisorJob() + Dispatchers.IO)
        }
    
        @Singleton
        @Provides
        fun provideDao(@ApplicationContext applicationContext: Context, scope: CoroutineScope) : MyDAO {
            return MyDB.getDatabase(
                applicationContext,
                scope
            ).myDAO
        }