androiddagger-2subcomponent

Dagger 2 Adding a subcomponent to a parent component


Hi community I have problem with understanding dagger 2 adding subcomponent in the new way (added in dagger 2.7). See example below:

@Component(modules = {AppModule.class, MainActivityBinder.class})
@Singleton
interface AppComponent
{
   inject(MyApplication _)
}

@Subcomponent(modules = ActivityModule.class)
interface ActivitySubcomponent
{
   inject(MainActivity _)

   @Subcomponent.Builder
   interface Builder
   {
      @BindInstance
      Builder activity(Activity activity)

      ActivitySubcomponent build();
   }
}

Initial step: I have AppComponent with is my root component, that provide AppModule with singletons (retrofit, okhttp etc.) In ActivitySubcomponent I provide ActivityModule with has dependencies specified to that activity. Now subcomponent must be added to AppComponent, so in new way I create specified module called MainActivityBinder, that has annotations @Module.subcomponents with point to that binds subcomponent, but I have first problem, what should be in body of that bind module ?

@Module(subcomponents = ActivitySubcomponent.class)
public class MainActivityBinder
{
  //what body of this class should be ??
}

I know, that idea is that I can bind subcomponent or their builder. Second question when bind builder, and when bind subcomponent ? For example my ActivitySubcomponent required activity context, so I create builder that provide context to ActivityModule in this case will be better to provide in MainActivityBinder a builder ? Third question how invoke component builder and how obtain subcomponent for app component ? In standard subcomponent factory I added to AppComponent method that return subcomponent and I can define params (for example give activity context, listed below)

@Component(modules = {AppModule.class})
@Singleton
interface AppComponent
{
   ActivitySubcomponents newActivitySubcomponents(Activity activity);

   inject(MyApplication _);
}

// in MainActivity
appComponent.newActivitySubcomponents(this).build().inject(this);

so have achieve this behavior in new subcomponent added method ?


Solution

    1. Your module MainActivityBinder is allowed to be empty, and should be if you don't have anything else to bind with it. Empty (annotation-only) modules are also useful when you only use Module.includes, such as when you want to keep a module list in one place rather than duplicating it among several components. The subcomponents attribute on the annotation is enough for Dagger to understand what you're trying to do.

    2. You can inject a FooSubcomponent or Provider if and only if it has no @BindsInstance methods or instantiable modules (that Dagger can't instantiate). If all of your modules are interfaces, abstract classes, or modules that have public zero-arg constructors, then you may inject the subcomponent directly. Otherwise you should inject your subcomponent builder instead.

    3. You can get to your subcomponent builder by creating a method that returns it on your AppComponent, just as you can for any binding that exists in the graph:

      @Component(modules = {AppModule.class, MainActivityBinder.class})
      @Singleton
      interface AppComponent {
        ActivitySubcomponent.Builder activitySubcomponentBuilder();
      
        inject(MyApplication _)
      }
      

      You may also inject it into the object of your choice.

      @Inject ActivitySubcomponent.Builder activitySubComponentBuilder;
      activitySubComponentBuilder.activity(this).build().inject(this);
      
      // You can also inject a Provider<ActivitySubcomponent.Builder> if you want,
      // which is a good idea if you are injecting this directly into your Application.
      // Your Application will outlive your Activity, and may need to inject several
      // instances of the Activity across application lifetime.
      @Inject Provider<ActivitySubcomponent.Builder> activitySubComponentBuilderProvider;
      activitySubComponentBuilderProvider.get().activity(this).build().inject(this);
      

    Though there doesn't appear to be much advantage to injecting the subcomponent builder when you could just as easily call the method on the component (either to return the Builder or return the subcomponent), there are a couple of advantages to injecting the builder: