Mel
Mel

Reputation: 1820

Dagger subcomponent with contributor

I'm having trouble injecting a fragment that I contribute via @ContributesAndroidInjector.

I'm trying to build a hierarchy within modules (features). Basically, what I have is:

My AppComponent depends on CoreComponent:

@Singleton
@Component(modules = [CoreModule::class])
interface CoreComponent {

    fun getApp(): Application

    @Component.Factory
    interface Factory {
        fun create(@BindsInstance app: Application): CoreComponent
    }
}

And initialize as:

@AppScope
@Component(
    modules = [
        AndroidInjectionModule::class,
        ActivityContributor::class,
        AppModule::class],
    dependencies = [CoreComponent::class]
)
interface AppComponent : AndroidInjector<App> {

    @Component.Factory
    interface Factory {
        fun create(component: CoreComponent): AppComponent
    }
}

This part is pretty much straightforward. AppComponent has ActivityContributor which only has one @ContributesAndroidInjector, which is MainActivity.

Now, problem starts when I want to add an encapsulated feature subcomponent. Assume I have two fragments FragmentOne and FragmentTwo in my feature, with some common dependencies as well as their own.

What I want to have is a FeatureSubcomponent which has FeatureModule and FeatureContributor:

@FeatureScope
@Subcomponent(
    modules = [FeatureContributor::class,
        FeatureModule::class
    ]
)
abstract class FeatureSubcomponent {

    @Subcomponent.Factory
    interface Factory {
        fun create(): FeatureSubcomponent
    }
}

While FeatureModule has dependencies common for both fragments, FeatureContributor is contributing FragmentOne and FragmentTwo with their own modules:

@Module
abstract class FeatureContributor {

    @ContributesAndroidInjector(modules = [FeatureOneModule::class])
    abstract fun featureOneFragment(): FeatureOneFragment

    @ContributesAndroidInjector(modules = [FeatureTwoModule::class])
    abstract fun featureTwoFragment(): FeatureTwoFragment
}

And of course, I add FeatureSubcomponent as a subcomponent to AppModule:

@Module(subcomponents = [FeatureSubcomponent::class])

And if you scroll up, you'll see AppModule is included in modules of AppComponent.

Problem is, while it's compiling and running, it crashes once it reaches to any feature fragments due to No injector factory bound for error.

Roughly summarising my structure:

Anyone has ideas about why or how it should be instead or am I missing something ?

Edit

Here's the diagram I prepared to make it easier to understand hierarchy

Dagger hierarchy diagram

Upvotes: 4

Views: 1137

Answers (1)

Arun
Arun

Reputation: 760

Dagger android does injection by finding the closest injector in the current scope. For Fragment, it is the containing Activity and for Activity it is the Application instance.

When you call AndriodInject.inject(this) in the Fragment it is goes up the hierarchy to find injector and then injects the Fragment.

Have you extended DaggerAppCompatActivity/implemented the HasFragmentInjector?

Another thing I see is, why create subcomponent again when @ContributesAndroidInjector already creates a sub component internally for you?

@ContributesAndroidInjector.modules is a way for talking to the generated subcomponent. So the relationship between Activity and FeatureFragment must be established in the subcomponent that the @ContributesAndroidInjector will be generating.

Right now your hierarchy is like this since you have deliberately specified FeatureSubComponent to be subcomponent of the AppComponent

App -> FeatureSubComponent -> [A, B] (generated)
      \
       \---> MainActivitySubcomponent (generated by contributesAndroidInjector).

What you actually need is:

App -> MainActivitySubComponent (generated) -> [Feature A , Feature B] (generated)

To do this

@ContributesAndroidInjector(modules = [FeatureContributor::class])
abstact fun mainActivity() : MainActivity

Feature contributor can have @ContributesAndroidInjectors inside. When Dagger compiler sees that FeatureContributor has @ContributesAndroidInjectors, it makes the subcomponent generated by those to be the subcomponent of the activity since it is the parent.

Which basically means Activity -> Fragment hierarchy.

Upvotes: 4

Related Questions