Dagger 2.10 Android subcomponents and builders

In short, you’re supposed to override the call to seedInstance on the Builder (which is an abstract class instead of an interface) to provide other modules you need.

edit: Before you do, check and make sure that you really need to pass that Module. As Damon added in a separate answer, if you’re making a specific Module for your Android class, you can rely on the automatic injection of that class to pull the configuration or instance out of the graph at that point. Favor his approach if it’s easier just to eliminate the constructor parameters from your Module, which also may provide better performance as they avoid unnecessary instances and virtual method calls.


First, dagger.android in 30 seconds: Rather than having each Activity or Fragment know about its parent, the Activity (or Fragment) calls AndroidInjection.inject(this), which checks the Application for HasActivityInjector (or parent fragments, activity, and application for HasFragmentInjector). The idea is that you contribute a binding to a multibindings-created Map<Class, AndroidInjector.Factory>, where the contributed bindings are almost always subcomponent builders you write that build object-specific subcomponents.

As you might tell from AndroidInjection.inject(this) and AndroidInjector.Factory.create(T instance), you don’t get a lot of opportunity to pass Activity-specific or Fragment-specific details to your Builder. Instead, the idea is that your subcomponent builder overrides the seedInstance implementation. As in the docs for seedInstance:

Provides instance to be used in the binding graph of the built AndroidInjector. By default, this is used as a BindsInstance method, but it may be overridden to provide any modules which need a reference to the activity.

This should be the same instance that will be passed to inject(Object).

That’d look something like this:

@Subcomponent(modules = {OneModule.class, TwoModule.class})
public interface YourActivitySubcomponent extends AndroidInjector<YourActivity> {

  // inject(YourActivity) is inherited from AndroidInjector<YourActivity>

  @Builder
  public abstract class Builder extends AndroidInjector.Builder<YourActivity> {
    // Here are your required module builders:
    abstract Builder oneModule(OneModule module);
    abstract Builder twoModule(TwoModule module);

    // By overriding seedInstance, you don't let Dagger provide its
    // normal @BindsInstance implementation, but you can supply the
    // instance to modules or call your own BindsInstance:
    @Override public void seedInstance(YourActivity activity) {
      oneModule(new OneModule(activity));
      twoModule(new TwoModule(activity.getTwoModuleParameter()));
    }
  }
}

The assumption here is that you need to wait for the activity instance for the modules. If not, then you also have the option of calling those when you bind the subcomponent:

@Provides @IntoMap @ActivityKey(YourActivity.class)
AndroidInjector.Factory bindInjector(YourActivitySubcomponent.Builder builder) {
  return builder
      .oneModule(new OneModule(...))
      .twoModule(new TwoModule(...));
}

…but if you can do that, then you could more-easily take care of those bindings by overriding those modules, implementing a zero-arg constructor that can supply the Module’s constructor parameters, and letting Dagger create those as it does for any Modules with public zero-arg constructors.

Leave a Comment

tech