【问题标题】:Dagger 2 subcomponents vs component dependenciesDagger 2 子组件 vs 组件依赖
【发布时间】:2015-06-17 16:32:51
【问题描述】:

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

在什么情况下使用组件依赖而不是子组件依赖会有好处,为什么?

【问题讨论】:

    标签: dagger dagger-2


    【解决方案1】:

    组件依赖 - 当你想保持两个组件独立时使用它。

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


    我将使用下面的例子来解释组件依赖子组件。该示例值得注意的几点是:

    • SomeClassA1 可以在没有任何依赖关系的情况下创建。 ModuleA 通过provideSomeClassA1() 方法提供SomeClassA1 的实例。
    • 没有SomeClassA1,就无法创建SomeClassB1。仅当 SomeClassA1 的实例作为参数传递给 provideSomeClassB1() 方法时,ModuleB 才能提供 SomeClassB1 的实例。
    @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;
        }
    }
    

    每当声明ModuleB 的组件/子组件被初始化时,Dagger 将负责将SomeClassA1 的实例作为参数传递给ModuleB 上的provideSomeClassB1() 方法。我们需要指示 Dagger 如何实现依赖。这可以通过使用组件依赖子组件来完成。

    组件依赖

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

    • 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 注释。
    • ComponentA 已经通过接口方法componentB() 声明了ModuleB。这使得这两个组件耦合。其实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);
        }
    }
    

    【讨论】:

    • 我有一个子组件设置,它没有将 Module B 添加到 ComponentA ,这意味着 componentA 构建器不需要 moduleB。这似乎按照我预期的方式工作,允许在应用程序启动时创建 ComponentA 然后实例化 m
    • @MikeN - 你能强调一下如何摆脱 ComponentA 上的 ModuleB 吗?只有在 ComponentA 和 ComponentB 上提供不同的作用域时,我才能摆脱 ComponentA 上的 ModuleB。
    • 你说得对,我的设置有效,因为它们在不同的范围内。道歉。
    • "SomeClassB1 依赖于 SomeClassA1ComponentA 必须明确定义依赖关系。" ==> 你的意思是“ComponentB 必须明确定义依赖”?
    • 与@Tar 指出的类似,我理解“SomeClassB1 依赖于SomeClassA1ComponentA 不需要明确定义依赖关系。”你的意思是“ComponentB 不需要明确定义依赖关系。”
    【解决方案2】:

    根据documentation

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

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

    假设您有一个ApplicationComponent,其中包含所有与Android 相关的内容(LocationServiceResourcesSharedPreference 等)。您还希望拥有您的DataComponent 来管理持久性事物以及WebService 来处理API。 DataComponent 中唯一缺少的是 Application Context,它位于 ApplicationComponent 中。从DataComponent 获取Context 的最简单方法是依赖ApplicationComponent。您需要确保在ApplicationComponent 中明确声明了Context,因为您只能访问已声明的内容。在这种情况下,无需手动操作,这意味着您无需在父级 Component 中指定 Submodules 并将子模块显式添加到父模块中,例如:

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

    现在考虑您想将WebServiceDataComponentLocationServiceApplicationComponent 注入到您的Fragment 的情况,该@Submodule 使用上面的plus 功能绑定。这里很酷的是,您绑定到 (ApplicationComponent) 的组件确实不需要 需要公开 WebServiceLocationService,因为您可以立即访问整个图表。 p>

    【讨论】:

    • 如果我理解正确的话,没有名为@Submodule的接口。是不是笔误?
    • 我喜欢它如何使用现实生活中的例子来展示差异。但是,这比阅读文档更令人困惑。少用classes作为例子,多用图片来说明确切的点会有所帮助。
    【解决方案3】:

    下面是代码示例和截图,可以让你更了解组件和子组件:

    组件:

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

    子组件:

    1. AppComponent 包含一个或多个子组件。
    2. AppComponent 初始化为 App 类。
    3. SubComponent 不知道他的 ParentComponent。仅通过包含 Module 来提供自己的依赖项。
    4. 在 HomeActivity 中,我使用父组件注入子组件。

    还有图解:

    来源:link

    【讨论】:

    • 如果子组件包含了 AppComponent 是不是更有意义?
    【解决方案4】:

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

    • @Subcomponent 实例只有一个父组件(尽管不同的组件可以实例化相同的 @Subcomponent 并成为该实例的父组件)
    • @Component 可能有零个、一个或多个通过component dependencies 声明的“父”组件

    【讨论】:

    • 可能在第二种情况下,说“@Component”可能有......父母是不正确的。相反,'@Component' 没有父级,但其他可能通过组件依赖项依赖于它(只需使用它)。
    • @demaksee 我不知道,在我看来,如果你绘制出你的组件层次结构,你就会得到 DAG,我认为这是一种将这种关系称为父关系的标准方式- 图形上下文中的子级。如果我们在谈论 Dagger 的内部运作,那么我想这可能不是正确的词。
    猜你喜欢
    • 2015-08-07
    • 2017-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多