Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error while trying to inject ViewModelProvider into Activity with Dagger2 and Kotlin

I'm receiving following error while trying to inject ViewModelProvider.Factory into Activity:

e: D:\AndroidStudioProjects\VolleyballStats\app\build\tmp\kapt3\stubs\debug\com\example\kamil\volleyballstats\di\AppComponent.java:6: error: [dagger.android.AndroidInjector.inject(T)] java.util.Map<java.lang.Class<? extends android.support.v4.app.Fragment>,javax.inject.Provider<dagger.android.AndroidInjector.Factory<? extends android.support.v4.app.Fragment>>> cannot be provided without an @Provides-annotated method.
e: 

e: public abstract interface AppComponent extends dagger.android.AndroidInjector<com.example.kamil.volleyballstats.VolleyballStatsApp> {
e:                 ^
e:       java.util.Map<java.lang.Class<? extends android.support.v4.app.Fragment>,javax.inject.Provider<dagger.android.AndroidInjector.Factory<? extends android.support.v4.app.Fragment>>> is injected at
e:           dagger.android.DispatchingAndroidInjector.<init>(injectorFactories)
e:       dagger.android.DispatchingAndroidInjector<android.support.v4.app.Fragment> is injected at
e:           dagger.android.support.DaggerAppCompatActivity.supportFragmentInjector
e:       com.example.kamil.volleyballstats.views.main.MainActivity is injected at
e:           dagger.android.AndroidInjector.inject(arg0)

I've created pretty standard Dagger2 implementation, which looks like this:

@Singleton
@Component(modules = arrayOf(
        AndroidInjectionModule::class,
        AppModule::class,
        MainActivityModule::class))
interface AppComponent : AndroidInjector<VolleyballStatsApp> {

@Component.Builder
interface Builder {
    @BindsInstance
    fun application(application: VolleyballStatsApp): Builder
    fun build(): AppComponent
}

override fun inject(app: VolleyballStatsApp)
}

@Module
abstract class ViewModelModule {

    @Binds
    @IntoMap
    @ViewModelKey(MainViewModel::class)
    abstract fun bindMainViewModel(viewModel: MainViewModel): ViewModel

    @Binds
    abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
}

@Module(includes = arrayOf(ViewModelModule::class))
class AppModule {

    @Provides
    fun provideDisposable(): CompositeDisposable {
        return CompositeDisposable()
    }
}

@Module
internal abstract class MainActivityModule {

    @ContributesAndroidInjector(modules = arrayOf(FragmentBuilders::class))
    internal abstract fun contributeMainActivity(): MainActivity
}

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@MapKey
internal annotation class ViewModelKey(val value: KClass<out ViewModel>)



class ViewModelFactory @Inject constructor(private val creators: @JvmSuppressWildcards Map<Class<out ViewModel>, @JvmSuppressWildcards 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 {
            @Suppress("UNCHECKED_CAST")
            return creator.get() as T
        } catch (e: Exception) {
            throw RuntimeException(e)
        }
    }
}

My MainActivity is defined as following:

class MainActivity : BaseActivity() {
    @Inject lateinit var viewModelFactory: ViewModelProvider.Factory
    private lateinit var viewModel: MainViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        viewModel = ViewModelProviders.of(this, viewModelFactory).get(MainViewModel::class.java)
    }
}

Here is MainViewModel class:

class MainViewModel @Inject constructor(private val disposable: CompositeDisposable) : ViewModel() {
}

And finally App class:

class VolleyballStatsApp : DaggerApplication() {

    override fun applicationInjector() = DaggerAppComponent.builder()
            .application(this)
            .build()
}

I've been following Android Architecture Components Sample from Google repository and I think everything seems to be similar to that implementation, so I don't get why this is not working.

When I'm trying to inject Application to MainAcitvity then it's working, so the problem is definitely with ViewModelProvider.Factory, but unfortunately I don't know where the problem is.

like image 534
user3448282 Avatar asked Dec 04 '25 18:12

user3448282


1 Answers

My guess is that you missed the AndroidSupportInjectionModule. Add it to the list of modules in your AppComponent. I can't really tell because you did not post your BaseActivity.

Reference: https://github.com/google/dagger/issues/783.

like image 100
mcassiano Avatar answered Dec 06 '25 09:12

mcassiano



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!