为什么使用@ Module.subcomponents比通过父组件上的方法安装子组件更好?

时间:2019-04-08 19:33:02

标签: dependency-injection module dagger-2 dagger subcomponent

来自docs

  

使用@Module.subcomponents更好,因为它允许Dagger检测是否曾经请求子组件。通过方法在父组件上安装子组件是对该组件的显式请求,即使从未调用该方法也是如此。 Dagger无法检测到它,因此即使您从不使用它也必须生成子组件。

有人知道这到底是什么意思吗?

1 个答案:

答案 0 :(得分:2)

Dagger不能告诉您是否曾经调用过任何组件方法:这是一个编译时框架,它生成组件实现,并且实现您放置在组件接口上的每个方法。

@Component(modules = YourModule.class)
public interface YourComponent {
  ClassA a();
  ClassB b();

  ExplicitSubcomponent createExplicitSubcomponent(Dep1 dep1, Dep2 dep2);
}

@Module(subcomponents = ImplicitSubcomponent.class)
public abstract class YourModule {
  @Binds ClassC classC(DefaultClassC classCImpl);
}

在上面的示例中,我们有ClassA,ClassB和ClassC。可以说,在所有这些中,您实际上只需要ClassA:它们实际上并不相互依赖,并且您实际上没有使用子组件。

  • Dagger实现了ClassA的绑定和ClassA的依赖关系的传递式闭合,这很好,因为您需要它!您将其放在组件接口上,以便Dagger可以为您创建实现,包括所有ClassA依赖项。
  • Dagger实现了对ClassB的绑定,这不是必需的,但Dagger不能告诉:它仅知道b()已定义,因此有人可能会在某天打电话要求ClassB。 Dagger无法了解是否有人调用b(),因此它必须创建和引用ClassB以及ClassB传递依赖的所有内容的工厂实现。
  • Dagger没有实现对ClassC的绑定,因为即使您已绑定它,也没有人要求。它在界面上不可用,并且没有人在内部要求它,因此Dagger可以安全地忽略它。

这说明了Dagger的哲学,即仅编译可从组件接口本身访问的内容。这也适用于子组件:

  • Dagger为ExplicitSubcomponent创建一个实现,因为像ClassB一样,您已将其绑定在接口上。有人可能会要求它。
  • 在从ClassA或ClassB可以访问之前,Dagger不会为ImplicitSubcomponent创建实现。 一旦您做,它就会做。如果没有人要求ImplicitSubcomponent,则Dagger不会为其生成代码。

当然,如果您要使用Proguard或其他静态分析器修剪构建,则这些工具可能能够修剪不必要的类或方法。但是,此时您正在进行代码生成子组件的工作,正在进行将其编译为字节码的工作,然后Proguard正在进行将其删除的工作。如果您在知道自己需要子组件之前就避免编译子组件,那么在大型项目中效率会更高。