I'm new to DI and recently started using dagger2 in my project. I'm able to provide repositories and use ViewModelFactory for my fragment, but I can't get an idea of how to provide ApplicationContext into my ViewModel. I need it to access SharePreferenceHelper class.
Here is my dagger2 implementation:
Where exactly should I create provide fun for appContext and how to Inject it from ViewModel?
I know this is a long code snippet, but would be grateful if someone could take a look.
ApplicationComponent:
@Singleton
@Component(
modules = [
ApplicationModule::class,
AndroidSupportInjectionModule::class,
SettingsModule::class
]
)
interface ApplicationComponent : AndroidInjector<MyApplication> {
@Component.Factory
interface Factory {
fun create(@BindsInstance applicationContext: Context): ApplicationComponent
}
}
ApplicationModule:
@Module
class ApplicationModule {
@Singleton
@Provides
fun provideAssetsRepository(context: Context): AssetsRepository {
return AssetsRepository(
AppDatabase.getDatabase(context.applicationContext).assetDao()
)
}
@Singleton
@Provides
fun provideExpensesRepository(context: Context): ExpensesRepository {
return ExpensesRepository(
AppDatabase.getDatabase(context.applicationContext).expenseDao()
)
}
@Singleton
@Provides
fun provideTransactionsRepository(context: Context): TransactionsRepository {
return TransactionsRepository(
AppDatabase.getDatabase(context.applicationContext).transactionsDao()
)
}
}
MyApplication:
open class MyApplication : DaggerApplication() {
override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
return DaggerApplicationComponent.factory().create(applicationContext)
}
}
SettingsModule:
@Module
abstract class SettingsModule {
@ContributesAndroidInjector(
modules = [
ViewModelBuilder::class]
)
internal abstract fun settingsFragment(): SettingsFragment
@Binds
@IntoMap
@ViewModelKey(SettingsViewModel::class)
internal abstract fun bindViewModel(viewModel: SettingsViewModel): ViewModel
}
ViewModelFactory:
class ViewModelFactory @Inject constructor(
private val creators: @JvmSuppressWildcards Map<Class<out ViewModel>, Provider<ViewModel>>
) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
var creator: Provider<out ViewModel>? = creators[modelClass]
if (creator == null) {
for ((key, value) in creators) {
if (modelClass.isAssignableFrom(key)) {
creator = value
break
}
}
}
if (creator == null) {
throw IllegalArgumentException("Unknown model class: $modelClass")
}
try {
return creator.get() as T
} catch (e: Exception) {
throw RuntimeException(e)
}
}
}
@Module
internal abstract class ViewModelBuilder {
@Binds
internal abstract fun bindViewModelFactory(
factory: ViewModelFactory
): ViewModelProvider.Factory
}
@Target(
AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER
)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>)