How to declare activities and fragments for non-base feature modules?
As we had only a base feature module and a single feature module, we could declare the App
class in the feature module and had our graph be loaded there. This meant being able to use ContributesAndroidInjector
and the standard dagger approach for android.
Now, adding more feature modules, we can't do the same. The application class must stay in the base feature module, which means it can't declare, for example, activities belonging to features.
My thoughts:
Since
AndroidInjection.inject(this)
will look for the activity injector in the app class, we can't use it. In other words, noDaggerAppCompatActivity
.So the idea is that activities belonging to feature modules should, instead, create their own component and inject themselves.
Still, it should be possible for fragments to use the
@ContributesAndroidInjector
thing. Right? TheAndroidInjection
class will get the injector from the parent activity, so if we fix our activities, they will expose the correct injector so that fragment code can be left as is.For this reason, the feature activities must implement
HasFragmentInjector
and have a@Inject
annotatedDispatchingAndroidInjector
for fragments.
But two things don't work here.
Feature fragments and activities still need some
@Singleton
annotated objects from the base feature component graph, so ourSpecialFeatureComponent
must somehow be linked to theBaseFeatureComponent
.It seems that the only way of doing so is by using the
dependencies
parameter:@Component( dependencies = [BaseFeatureComponent::class], modules = [SpecialFeatureModule::class] // @contributes fragment ) interface SpecialFeatureComponent
The
SpecialActivity
creates this component, passes theBaseFeatureComponent
to its builder, and injects itself.However, compilation fails due to
MissingBinding
errors. Some of the objects in the special feature module need@Provide
,@Singleton
annotated objects from the base feature component, and dagger doesn't seem to find them properly. (these objects are not inBaseFeatureComponent
, but rather in its attached modules)How to fix this?
I have read that exposing them directly in
BaseFeatureComponent
, rather than in its dependency modules, should fix the issue, but it's not something we would like to do, as there are lots of them and it would be yet another list to be maintained.
As is, the unscoped
SpecialFeatureComponent
depends on the@Singleton
scopedBaseFeatureComponent
. This is not possible, so we have to add aActivityScope
annotation.@ActivityScope @Component( dependencies = [BaseFeatureComponent::class], modules = [SpecialFeatureModule::class] // @contributes fragment ) interface SpecialFeatureComponent
Now we are told that the subcomponents generated by
@ContributesAndroidInjector
for fragments, unscoped, may not reference scoped bindings. So we add a@FragmentScope
annotation there.@Module abstract class SpecialFeatureModule { @FragmentScope @ContributesAndroidInjector internal abstract fun specialFragment(): SpecialFragment }
Now we are told that these subcomponents may not reference bindings with a different scope! Which are
@Singleton
objects provided by the base feature graph.