Dagger 2 ContributesAndroidInjector provides module activity

I am trying to find a less constructive use of the ActivityModule , which is used in all my applications. This is my current setup:

Activitymodule

 @Module class ActivityModule(private val activity: Activity) { @Provides @ActivityScope fun providesActivity(): Activity = activity @Provides @ActivityContext @ActivityScope fun providesContext(): Context = activity @Provides @ActivityContext @ActivityScope fun providesLayoutInflater(): LayoutInflater = activity.layoutInflater @Provides @ActivityContext @ActivityScope fun providesResources(): Resources = activity.resources } 

AppActivityModule (provides actions for AndroidInjectionModule)

 @Module(subcomponents = [ AppActivityModule.WelcomeActivityComponent::class ]) internal abstract class AppActivityModule { @Binds @IntoMap @ActivityKey(WelcomeActivity::class) abstract fun bindWelcomeActivityInjectorFactory(builder: WelcomeActivityComponent.Builder): AndroidInjector.Factory<out Activity> @ActivityScope @Subcomponent(modules = [(ActivityModule::class)]) interface WelcomeActivityComponent : AndroidInjector<WelcomeActivity> { @Subcomponent.Builder abstract class Builder : AndroidInjector.Builder<WelcomeActivity>() { abstract fun activityModule(myActivityModule: ActivityModule): AndroidInjector.Builder<WelcomeActivity> override fun seedInstance(instance: WelcomeActivity) { activityModule(ActivityModule(instance)) } } } } 

Instead, I want the AppActivityModule to be:

 @Module internal abstract class AppActivityModule { @ContributesAndroidInjector(modules = [(ActivityModule::class)]) abstract fun contributeWelcomeActivityInjector(): WelcomeActivity } 

But this, quite understandably, gives me the error /di/AppActivityModule_ContributeWelcomeActivityInjector.java:29: error: @Subcomponent.Builder is missing setters for required modules or subcomponents: [...di.modules.ActivityModule]

My question is: is there a more capable way to achieve what I'm trying to do? I know about @Bind and @BindsInstance (from this answer ), but it seems to work only if I have a modular action and associate a specific kind of activity that I don't want in this case - I want the ActivityModule worked with all the actions.

+10
java android kotlin dagger dagger-2
source share
1 answer

One way to minimize the template is to create a common ActivityModule module, and then create a small specific module for each action. Forgive my Kotlin inexperience, but here goes:

 // Abstract class so you don't have to provide an instance @Module abstract class ActivityModule { // No need for ActivityScope: You're always binding to the same Activity, so // there no reason to have Dagger save your Context instance in a Provider. @Binds @ActivityContext abstract fun providesContext(activity: Activity): Context // This does not *have* to be in a companion object, but that way // Android can do a static dispatch instead of a virtual method dispatch. // If you don't need that, just skip the constructor arguments and make these // normal methods and you'll be good to go. @Module companion object { @JvmStatic @Provides @ActivityContext fun providesLayoutInflater(activity: Activity): LayoutInflater = activity.layoutInflater @JvmStatic @Provides @ActivityContext fun providesResources(activity: Activity): Resources = activity.resources } } 

And your module:

 @Module internal abstract class AppActivityModule { @Module internal interface WelcomeActivityModule { // The component that @ContributesAndroidInjector generates will bind // your WelcomeActivity, but not your Activity. So just connect the two, // and suddenly you'll have access via injections of Activity. @Binds fun bindWelcomeActivity(activity: WelcomeActivity) : Activity } @ContributesAndroidInjector( modules = [ActivityModule::class, WelcomeActivityModule::class]) abstract fun contributeWelcomeActivityInjector(): WelcomeActivity } 

Note that while this works for Activity, Service, BroadcastReceiver and others, you might not want to be so fast for Fragment. This is because dagger.android processes fragment hierarchies with parent fragments, so from a child component you can access YourApplication, YourActivity, YourParentFragment and YourChildFragment, as well as all their components. If something in YourChildFragmentComponent depends on an unqualified fragment, it would be ambiguous whether it really wants YourParentFragment or YourChildFragment. However, this design makes sense for actions and certain fragments, so it makes sense to use it (carefully).


UPDATE: What does @ActivityContext do here?

@ActivityContext here you can define a qualification annotation that you can use to distinguish between bindings of the same type in Dagger and other DI environments, presumably @ApplicationContext Context and @ActivityContext Context . It would be nice not to try it, but I strongly recommend saving it and avoiding unqualified context binding: application contexts and actions may differ, especially in multi-screen or automatic environments, and to get the right resources and data that you need to be accurate about which you use. You can use this as an example.

+5
source share

All Articles