Dagger: Dagger MissingBinding error when injecting ViewModels (dagger 2.24 with kotlin 1.3.50)

Created on 8 Sep 2019  Â·  7Comments  Â·  Source: google/dagger

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

Most helpful comment

Remove @Singleton on top of ViewModelFactory Class
move ViewModelModule into @ContributesAndroidInjector(modules = [MainModule::class,ViewModelModule ::class])

All 7 comments

@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 ?

Was this page helpful?
0 / 5 - 0 ratings