Francesc
Francesc

Reputation: 29260

Dagger2 dependent components

In my app I have a component with Application scope (same as Singleton) that provides a ViewModel Factory, and a dependent component with Activity scope that injects the factory in a fragment.

The application component is defined as follows:

@Component(modules = [AppModule::class, /* other stuff */, ViewModelModule::class])

@ApplicationScope
interface AppComponent {
    fun inject(app: Application)

    /* other stuff */

    val viewModelFactory: ViewModelFactory
}

The view model module is defined as follows:

@ApplicationScope
@Module
abstract class ViewModelModule {
    @Binds
    abstract fun bindViewModelFactory(viewModelFactory: ViewModelFactory): ViewModelProvider.Factory

    @Binds
    @IntoMap
    @ViewModelKey(DisplayEntryViewModelImpl::class)
    abstract fun bindDisplayEntryViewModel(displayEntryViewModelImpl: DisplayEntryViewModelImpl): ViewModel
}

The activity scope component is defined as follows:

@Component(dependencies = [AppComponent::class], modules = [DisplayEntryActivityModule::class])

@ActivityScope
interface DisplayEntryActivityComponent {
    fun inject(displayEntryActivity: DisplayEntryActivity)
    fun inject(displayEntryFragment: DisplayEntryFragment)
}

When I try to inject the viewmodel factory in the fragment I get this error:

error: android.arch.lifecycle.ViewModelProvider.Factory cannot be provided without an @Provides- or @Produces-annotated method.

If I update the activity component to include the view model module, like this

@Component(dependencies = [AppComponent::class], modules = [DisplayEntryActivityModule::class, ViewModelModule::class])

@ActivityScope
interface DisplayEntryActivityComponent {
    fun inject(displayEntryActivity: DisplayEntryActivity)
    fun inject(displayEntryFragment: DisplayEntryFragment)
}

Then it compiles. My understanding is that dependent components have access to the injected members from the parent component if the parent component explicitly provides those members, as I do here with the

 val viewModelFactory: ViewModelFactory

so why do I still need to provide the viewmodel module in the activity scope component?

Upvotes: 2

Views: 647

Answers (1)

Mumi
Mumi

Reputation: 351

When using dependencies, dagger will use that component to inject member.
Parent component must explicitly declare objects which can be used in child components.

@Component(modules = [AppModule::class, /* other stuff */, ViewModelModule::class])
@ApplicationScope  
interface AppComponent {
   fun inject(app: Application)

   fun viewModelFactory(): ViewModelProvider.Factory

   fun viewModel(): ViewModel
}

You can take a look at this article: https://proandroiddev.com/dagger-2-part-ii-custom-scopes-component-dependencies-subcomponents-697c1fa1cfc

Upvotes: 3

Related Questions