Setup
dagger v2.24
kotlin 1.3.50
Gradle 5.4.1
Error
error: [Dagger/MissingBinding] java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> cannot be provided without an @Provides-annotated method.
public abstract interface AppComponent extends dagger.android.AndroidInjector<com.champion.myproject.MainApplication> {
^
java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> is injected at
com.champion.myproject.di.ViewModelFactory(creators)
com.champion.myproject.di.ViewModelFactory is injected at
com.champion.myproject.di.module.ViewModelModule.bindViewModelFactory(factory)
androidx.lifecycle.ViewModelProvider.Factory is injected at
com.champion.myproject.ui.basemvvm.BaseAppCompatActivity.viewModelFactory
com.champion.myproject.ui.main.MainActivity is injected at
dagger.android.AndroidInjector.inject(T) [com.champion.myproject.di.AppComponent → com.champion.myproject.di.module.ActivityBindingModule_BindMainActivity.MainActivitySubcomponent]
Code
@Singleton
class ViewModelFactory @Inject constructor(
private val creators: Map<Class<out ViewModel>,
@JvmSuppressWildcards Provider<ViewModel>>
) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
val creator = creators[modelClass] ?: creators.entries.firstOrNull {
modelClass.isAssignableFrom(it.key)
}?.value ?: throw IllegalArgumentException("unknown model class $modelClass")
try {
@Suppress("UNCHECKED_CAST")
return creator.get() as T
} catch (e: Exception) {
throw RuntimeException(e)
}
}
}
@Module
abstract class ViewModelModule {
@Binds
abstract fun bindViewModelFactory(factory : ViewModelFactory) : ViewModelProvider.Factory
}
@Module
abstract class MainModule {
@Binds
@IntoMap
@ViewModelKey(MainViewModel::class)
abstract fun bindMainViewModel(mainViewModel: MainViewModel): ViewModel
}
@MustBeDocumented
@Target(
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER
)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>)
@Module
abstract class ActivityBindingModule {
@ContributesAndroidInjector(modules = [MainModule::class])
abstract fun bindMainActivity() : MainActivity
}
@Singleton
@Component(
modules = [
AndroidSupportInjectionModule::class,
AppModule::class,
ViewModelModule::class,
ActivityBindingModule::class,
ServiceModule::class,
UtilModule::class
]
)
interface AppComponent : AndroidInjector<MainApplication> {
@Component.Factory
interface Factory : AndroidInjector.Factory<MainApplication>
}
if inject other class is not problem
@champChayangkoon I'm fairly certain you're hitting this issue: #900 (comment). Would suggest reading that thread and using the advice there for working around this
I think the above is right and this is an @JvmSuppressWildcards issue.
@champChayangkoon do you solve this problem? I hava met the same problem?
I am facing the same issue.Please can you share the solution.I had already added @JvmSuppressWildcards even though I am facing the issue
Remove @Singleton on top of ViewModelFactory Class
move ViewModelModule into @ContributesAndroidInjector(modules = [MainModule::class,ViewModelModule ::class])
Remove @singleton on top of ViewModelFactory Class
move ViewModelModule into @ContributesAndroidInjector(modules = [MainModule::class,ViewModelModule ::class])
Right, but then the ViewModel Factory will not be singleton scoped and will be a separate instance every time, which defeats the purpose.
Remove @singleton on top of ViewModelFactory Class
move ViewModelModule into @ContributesAndroidInjector(modules = [MainModule::class,ViewModelModule ::class])Right, but then the ViewModel Factory will not be singleton scoped and will be a separate instance every time, which defeats the purpose.
Any solution ?
Most helpful comment
Remove @Singleton on top of ViewModelFactory Class
move ViewModelModule into @ContributesAndroidInjector(modules = [MainModule::class,ViewModelModule ::class])