Dagger 2.10 Android subcomponents and builders

前端 未结 2 1732
囚心锁ツ
囚心锁ツ 2020-11-27 13:41

Using the new (in 2.10) dagger.android classes, I\'m trying to inject things using a Subcomponent that depends on other Modules, and, therefore, has a Builder with setters f

相关标签:
2条回答
  • 2020-11-27 13:55

    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.

    0 讨论(0)
  • 2020-11-27 14:08

    that does work, but it's unnecessary. the seedInstance method provides the activity instance into the graph, so you can have MyActivityModule with no state, and just request MyActivity in your @Provides methods.

    class MyActivityModule {
      @Provides
      static SomethingDerivedFromMyActivity providesMethod(MyActivity myActivity) {
        return myActivity.somethingDerived();
      }
    }
    

    Doing this saves the module instance and allows the generated factories to be leaner.

    from https://github.com/google/dagger/issues/615.

    0 讨论(0)
提交回复
热议问题