Reputation: 1820
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
Upvotes: 4
Views: 1137
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