Dagger 2.10 Android子组件和构建器

17
使用新的(2.10中的)dagger.android类,我正在尝试使用依赖于其他模块的Subcomponent来注入内容,并且因此具有带有这些模块设置器的Builder。 https://google.github.io/dagger/android.html上的文档描述了这一点,但并不清楚如何实际编写和/或调用这些setter。
从上面的链接中引用:
AndroidInjection.inject()从应用程序获取DispatchingAndroidInjector,并将您的activity传递给inject(Activity)。 DispatchingAndroidInjector查找您的activity类的AndroidInjector.Factory(即YourActivitySubcomponent.Builder),创建AndroidInjector(即YourActivitySubcomponent),并将您的activity传递给inject(YourActivity)。
在我的看来,为了能够调用Builder的setters,我需要进入某个位置并确保Builder具有所有必要的数据?我看到的问题是,在运行时,当AndroidInjector调用生成的Subcomponent的builder时,我会得到一个IllegalStateException:MODULE必须设置。
所涉及的子组件实际上是针对片段而不是活动,但我不确定这是否重要。有关如何执行此操作的任何想法?

1
请查看这篇文章,很可能会解决你的问题。 - azizbekian
1
你能贴一些简化的代码吗?你无法设置哪个模块? - David Rawson
2个回答

30
简而言之,你需要在Builder上覆盖对seedInstance的调用(它是一个抽象类而不是接口),以提供其他所需的模块。 编辑:在此之前,请检查并确保您真的需要传递该模块。如Damon在另一个答案中所述,如果您为Android类制作了特定的模块,则可以依赖于自动注入该类来从图表中提取配置或实例。如果仅需消除构造函数参数,则应采用他的方法,这也可能提供更好的性能,因为它们避免了不必要的实例和虚拟方法调用。

首先,dagger.android 30秒速成:与其让每个Activity或Fragment知道其父级,Activity(或Fragment)调用AndroidInjection.inject(this),它会检查应用程序是否具有HasActivityInjector(或父片段、活动和应用程序是否具有HasFragmentInjector)。这个想法是你向一个由multibindings创建的Map<Class,AndroidInjector.Factory>贡献绑定,其中贡献的绑定几乎总是你编写的构建对象特定子组件的子组件构建器。

正如你从AndroidInjection.inject(this)AndroidInjector.Factory.create(T instance)中可以看出的那样,你没有太多机会将Activity特定或Fragment特定的详细信息传递给生成器。相反,这个想法是你的子组件构建器覆盖seedInstance实现。就像在seedInstance的文档中所述:

提供实例以在构建的AndroidInjector的绑定图中使用。默认情况下,它被用作BindsInstance方法,但它可以被覆盖以提供任何需要引用活动的模块。这应该是将传递给inject(Object)的相同实例。
看起来应该像这样:
@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()));
    }
  }
}

这里的假设是您需要等待模块的activity实例。如果不需要等待,则还可以在绑定子组件时调用它们的选项:
@Provides @IntoMap @ActivityKey(YourActivity.class)
AndroidInjector.Factory bindInjector(YourActivitySubcomponent.Builder builder) {
  return builder
      .oneModule(new OneModule(...))
      .twoModule(new TwoModule(...));
}

...但如果您能够做到这一点,那么您可以更轻松地通过覆盖这些模块来处理这些绑定,实现一个零参数构造函数来提供模块的构造函数参数,并让Dagger像处理任何具有公共零参数构造函数的模块一样创建它们。


4
太好了,它完全有效!然而这在文档中并没有提到,这让使用Dagger 2.+的新用户难以理解文档。 - ArunL
不确定为什么我的实现会返回一个错误,显示为“Error:(154,5)错误:方法未覆盖或实现超类型的方法”。 - Damon Yuan
根据 https://github.com/google/dagger/issues/615,```class MyActivityModule { @Provides static SomethingDerivedFromMyActivity providesMethod(MyActivity myActivity) { return myActivity.somethingDerived(); } }```已经足够好了。 - Damon Yuan
谢谢Damon!我已经评论了你的答案,并编辑了我的答案以包含对你的引用。 - Jeff Bowman
我认为我们想从 seedInstance 调用的那些方法需要声明为 public,否则 Dagger 会抱怨该方法“不是抽象方法且未覆盖抽象方法”。 - arekolek
显示剩余4条评论

3

虽然那样做是可行的,但并不必要。seedInstance方法将活动实例提供给图形,因此您可以在@Provides方法中请求MyActivity而无需使用状态的MyActivityModule。

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

这样做可以保存模块实例并使生成的工厂更加简洁。来源:https://github.com/google/dagger/issues/615

+1:你(和我的同事Ron)当然是正确的,前提是你的设置足够重构,可以编辑模块以包含对你的Activity的引用。如果你的模块来自第三方,或者设计用于处理不止你的MyActivity的多个Activities,则可能需要采用我更复杂的设置(这也在文档中建议)。我回答了这个问题,假设问者需要具有构造函数的有状态模块,因为他们提到了需要Builder,但如果你不需要,那么当然可以更轻松地表示事情。 - Jeff Bowman
1
同意,但我的问题是使用您的解决方案时,编译器会大声抗议“错误:(154,5)错误:方法不覆盖或实现超类型的方法”。我完全按照步骤操作,并在检查生成的代码后发现错误出现在oneModule()抽象方法的实现上。不确定为什么会发生这种情况,我正在使用dagger 2.10。无论如何,让我进行更多测试,也许我可以在我的代码中找到哪里出错了。 - Damon Yuan
你能给我展示一下吗?听起来像是oneModule没有被声明为public或abstract,或者类也没有被声明为这样的修饰符。 - Jeff Bowman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接