6

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, no DaggerAppCompatActivity.

  • 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? The AndroidInjection 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 annotated DispatchingAndroidInjector for fragments.

But two things don't work here.


  1. Feature fragments and activities still need some @Singleton annotated objects from the base feature component graph, so our SpecialFeatureComponent must somehow be linked to the BaseFeatureComponent.

    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 the BaseFeatureComponent 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 in BaseFeatureComponent, 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.


  1. As is, the unscoped SpecialFeatureComponent depends on the @Singleton scoped BaseFeatureComponent. This is not possible, so we have to add a ActivityScope 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.

How to fix this?

natario
  • 24,954
  • 17
  • 88
  • 158
  • _The application class must stay in the base feature module_ I don't see why this would be the case. Usually you'd have a base module, then feature modules that depend on base, and finally an app module that bundles everything together. If you move your Application implementation to the app module you can do all of AndroidInjection in feature modules as long as your App implements the injector interface – David Medenjak Aug 16 '18 at 22:30
  • 2
    @DavidMedenjak there is an instant app consuming these feature modules. Instant apps have no code, they just depend on features... So there's no bundling module that keeps everything together, each feature module must be independent – natario Aug 16 '18 at 22:53
  • Related, https://stackoverflow.com/q/45380163/4288782 but there's no answer to any of my two issues – natario Aug 16 '18 at 22:58

0 Answers0