Dagger 2子组件与组件依赖关系


135

Dagger 1的plus()方法是我在以前的应用程序中经常使用的方法,因此我了解到您可能希望拥有一个可以完全访问父图绑定的子组件的情况。

在什么情况下使用组件依赖关系而不是子组件依赖关系是有益的,为什么?

Answers:


228

组件依存关系-如果要使两个组件保持独立,请使用此选项。

子组件-当您要保持两个组件耦合时使用此组件。


我将使用下面的示例来说明Component依赖项Subcomponents。需要注意该示例的一些要点是:

  • SomeClassA1可以不受任何依赖地创建。ModuleA提供和的实例SomeClassA1经由provideSomeClassA1()方法。
  • SomeClassB1没有不能创建SomeClassA1。仅当将的一个实例作为方法的参数传递时,ModuleB才能提供的实例。SomeClassB1SomeClassA1provideSomeClassB1()
@Module
public class ModuleA {
    @Provides
    public SomeClassA1 provideSomeClassA1() {
        return new SomeClassA1();
    }
}

@Module
public class ModuleB {
    @Provides
    public SomeClassB1 provideSomeClassB1(SomeClassA1 someClassA1) {
        return new SomeClassB1(someClassA1);
    }
}

public class SomeClassA1 {
    public SomeClassA1() {}
}

public class SomeClassB1 {
    private SomeClassA1 someClassA1;

    public SomeClassB1(SomeClassA1 someClassA1) {
        this.someClassA1 = someClassA1;
    }
}

每当初始化组件/子组件声明时,Dagger都会将的实例SomeClassA1作为参数传递给provideSomeClassB1()方法。我们需要指导Dagger如何实现依赖关系。这可以通过使用Component依赖项Subcomponent来完成。ModuleBModuleB

组件依赖性

请注意以下“组件依赖关系”示例中的以下几点:

  • ComponentB必须通过注释dependencies方法定义依赖项@Component
  • ComponentA不需要声明ModuleB。这使两个组件保持独立。
public class ComponentDependency {
    @Component(modules = ModuleA.class)
    public interface ComponentA {
        SomeClassA1 someClassA1();
    }

    @Component(modules = ModuleB.class, dependencies = ComponentA.class)
    public interface ComponentB {
        SomeClassB1 someClassB1();
    }

    public static void main(String[] args) {
        ModuleA moduleA = new ModuleA();
        ComponentA componentA = DaggerComponentDependency_ComponentA.builder()
                .moduleA(moduleA)
                .build();

        ModuleB moduleB = new ModuleB();
        ComponentB componentB = DaggerComponentDependency_ComponentB.builder()
                .moduleB(moduleB)
                .componentA(componentA)
                .build();
    }
}

子组件

请注意SubComponent示例中的以下几点:

  • ComponentB尚未定义对的依赖ModuleA,它不能独立存在。它取决于将提供的组件ModuleA。因此,它具有@Subcomponent注释。
  • ComponentAModuleB通过接口方法声明componentB()。这使两个组件耦合。实际上,ComponentB只能通过进行初始化ComponentA
public class SubComponent {
    @Component(modules = ModuleA.class)
    public interface ComponentA {
        ComponentB componentB(ModuleB moduleB);
    }

    @Subcomponent(modules = ModuleB.class)
    public interface ComponentB {
        SomeClassB1 someClassB1();
    }

    public static void main(String[] args) {
        ModuleA moduleA = new ModuleA();
        ComponentA componentA = DaggerSubComponent_ComponentA.builder()
                .moduleA(moduleA)
                .build();

        ModuleB moduleB = new ModuleB();
        ComponentB componentB = componentA.componentB(moduleB);
    }
}

4
我有一个子组件设置,没有将模块B添加到ComponentA中,这意味着componentA构建器不需要moduleB。这似乎按我预期的方式工作,允许在应用程序启动时创建ComponentA,然后实例化m
FriendlyMikhail 2015年

2
@MikeN-您能强调一下如何在ComponentA上摆脱ModuleB吗?仅当我在ComponentA和ComponentB上提供不同的作用域时,才能摆脱ComponentA上的ModuleB。
Praveer Gupta 2015年

1
您是对的,因为它们位于不同的范围内,所以我的设置工作正常。道歉。
FriendlyMikhail

2
SomeClassB1依赖于SomeClassA1ComponentA必须显式定义依赖关系。” ==>您的意思是“ ComponentB必须显式定义依赖项”吗?
Tar

1
与@Tar所指出的类似,我理解in中“ SomeClassB1依赖于SomeClassA1ComponentA不需要显式定义依赖项”。您的意思是“ ComponentB无需显式定义依赖项”。
塞巴LG

45

根据文档

Component Dependency使您只能访问通过组件依赖项作为提供方法公开的绑定,即,您只能访问在parent中声明的类型Component

SubComponent声明时,可从其父级访问整个绑定图,即,您可以访问Modules中声明的所有对象。

比方说,你有一个ApplicationComponent包含所有Android相关的东西(LocationServiceResourcesSharedPreference等)。您还希望拥有DataComponent可以管理持久性以及WebService处理API的位置。您唯一缺少的DataComponentApplication Context驻留在中ApplicationComponent。得到一个最简单的方法ContextDataComponent将是对的依赖ApplicationComponent。您需要确保您有一个Context明确声明的进入,ApplicationComponent因为您只能访问声明的内容。在这种情况下,无需手动操作,这意味着您无需Submodules在父级中指定,也无需Component将子模块显式添加到父级模块中,例如:

MySubcomponent mySubcomponent = myComponent.plus(new ChildGraphModule("child!")); // No need!

现在考虑要注入这种情况下,WebServiceDataComponentLocationServiceApplicationComponent到您的Fragment使用结合@Submodule plus上述特征。这里的很酷的事情是,你结合(组件ApplicationComponent)并没有需要公开WebService,也不LocationService是因为你有机会获得整个图形的时候了。


2
如果我理解正确,则没有名为的接口@Submodule。是错字吗?
伊斯兰萨拉赫

我喜欢它如何使用现实生活中的例子来展示差异。但是,这比阅读文档更令人困惑。少classes一些示例,多一些图片来说明确切点会有所帮助。
sudocoder

18

这是带有屏幕截图的代码示例,用于更多地了解Component和SubComponent:

零件: 在此处输入图片说明

  1. AppComponent包含两个声明。
  2. AppComponent初始化为App类。
  3. HomeActivityComponent依赖于AppComponent。
  4. 在DaggerHomeActivityComponent初始化的HomeActivity中,我将AppComponent对象作为组合。

子组件:

在此处输入图片说明

  1. AppComponent包含一个或多个SubComponent。
  2. AppComponent初始化为App类。
  3. SubComponent不了解其ParentComponent。通过包含模块仅提供其自己的依赖性。
  4. 在HomeActivity中,我通过使用其父组件注入子组件。

和画图: 在此处输入图片说明

资料来源:链接


如果子组件包含在AppComponent中,该图是否更有意义?
Florian Walther

1

直到现在我还没有意识到的另一件事是:

  • 一个@Subcomponent实例只有一个父组件(尽管不同的组件可以实例化它@Subcomponent并成为该实例的父组件)
  • A @Component可能具有零个,一个或多个通过组件依赖项声明的“父”组件

1
可能在第二种情况下,说“ @Component”可能有...父代是不正确的。相反,“ @ Component”没有父项,但其他组件可能通过组件依赖项依赖于该父项(仅使用它)。
demaksee '18

@demaksee我不知道,在我看来,如果您映射出组件层次结构,您将获得DAG,并且我认为这是在图上下文中将此关系称为父子关系的标准方法。如果我们谈论的是Dagger的内部工作原理,那么我想这可能不是正确的词。
arekolek '18年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.