本文介绍了依赖于具有不同范围的其他组件的组件(具有不同范围的组件层次结构)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的Android项目中具有复杂的多层体系结构。

I have complex multi-tier architecture in my Android project.

目前,我想使用DI组件和模块的以下结构:

Currently i want to use the following structure of the DI components and modules:

[Data Layer]
    @DataScope //scope is used for caching (Singleton) some Data Layer entities for whole application
    - DataComponent //exposes just interfaces which should be used on the BL Layer
        //Modules exposes entities for internal (Data Layer) injections and entities which exposed by DataComponent for BL Layer
        * DataModule1
        * DataModule2
        * DataModule3

[Business Logic Layer] (also has component dependency on DataComponent)
    @BlScope //scope is used for caching (Singleton) some BL Layer entities for whole application
    - BlComponent //exposes just interfaces which should be used on the Service Layer & Presentation Layer
        //Modules exposes entities for internal (BL Layer) injections and entities which exposed by BLComponent for the Service Layer & Presentation Layer
        * BlModule1
        * BlModule2

[Service Layer] (also has component dependency on BlComponent) - this layer has Android specific entities (Android Service, ContentProvider) not related to the Presentation Layer
    @ServiceScope //scope is used for caching (Singleton) some Service Layer entities for whole application
    - ServiceComponent //exposes just interfaces which should be used on the Presentation Layer
        * ServiceModule //Module exposes entities for internal (Service Layer) injections and entities which exposed by ServiceComponent for the Presentation Layer

[Presentation Layer] (also has component dependency on: ServiceComponent, BlComponent)
    @PresentationScope //scope is used for caching (Singleton) some Presentation Layer entities for whole application
    - PresentationComponent //exposes just interfaces which should be used on the current layer
        * PresentationModule //Module exposes entities injections on the current layer

ServiceComponent& BlComponent不公开类似的接口。

The ServiceComponent & BlComponent don't expose the similar interfaces.

要构建主图,我使用以下代码:

To build the main graph i use the following code:

DataComponent dataComponent = DaggerDataComponent.builder().<addModules>.build();
BlComponent dataComponent = DaggerBlComponent.builder().<addModules>.dataComponent(dataComponent).build();
ServiceComponent serviceComponent = DaggerServiceComponent.builder().<addModule>.blComponent(blComponent).build();
PresentationComponent presentationComponent = DaggerPresentationComponent.builder().<addModule>.blComponent(blComponent).serviceComponent(serviceComponent).build();

在PresentationLayer中,我仅使用 presentationComponent来提供ServiceComponent / Layer和BLComponent / Layer所需的依赖项。

In the PresentationLayer i use only "presentationComponent" to provide required dependencies from ServiceComponent/Layer and BLComponent/Layer.

当前上面的方案不起作用,因为PresentationComponent依赖于两个作用域内的组件,错误为

Currently scenario above doesn't work, because PresentationComponent depends on the 2 scoped components with the error

尽管它允许将一个作用域组件与许多非作用域组件一起使用。该体系结构旨在限制在上层使用内部层实体,并同时在每个层/模块上具有独立的测试(单元和工具)。

Though it allows to use one scoped component with many non-scoped components. This architecture is directed to restrict to use internal layer entities on the upper layers and in the same time to have independent tests (unit & instrumentation) on each layer/module.

有人可以帮助我了解Dagger处理器的错误或理想行为吗? (以及为什么?)
Dagger2存储库上的问题:

Could anybody help me to understand is it bug or desirable behavior of the Dagger processor? (and why?)Issue on the Dagger2 repo: https://github.com/google/dagger/issues/747#issuecomment-303526785

推荐答案

不是一个错误,它是一个功能

以您建议的方式允许混合作用域所产生的问题类似于。

The problems that would emerge from allowing mixing scopes in the manner you have suggested are similar to the problems of multiple inheritance in OO languages.

请考虑以下组件结构(钻石问题):

Consider the following component structure (the diamond problem):

    A
   / \
  B   C
   \ /
    D

<$ c $ B C 的c> D 子组件。由于 B C 的兄弟姐妹彼此独立,因此可以自由公开任意依赖项 Foo 到子组件。假定在组件 D 中设置的模块需要 Foo D 现在应该使用哪个 Foo ?来自 B 的一个还是来自 C 的一个?

D sub-component of both B and C. Since siblings B and C are independent of each other they are free to expose an arbitrary dependency Foo to sub-components. Assume that Foo is required for the module set in component D. Which Foo should D now use? The one from B or the one from C?

如果您允许使用范围,情况会更加复杂。 Dagger 2中的作用域用于标记生命周期。换句话说,它说:这时我将保留对这些绑定的引用。因此,您的 @Singleton 范围内的绑定必须分组在一个Component中,在Application子类级别上为其维护引用。例如,将 @AppScoped 组件初始化为方法中的局部变量或Activity的字段,它什么都不做-它将与方法堆栈或活动销毁时销毁。

The situation is even more complex if you allow scopes. A scope in Dagger 2 is for marking lifecycle. In other words, it says "I will maintain a reference to these bindings at this point". Hence, your @Singleton scoped bindings must be grouped in a Component for which you maintain a reference at the level of your Application subclass. It does nothing, for instance, to initialise a @AppScoped Component as a local variable within a method or as a field of an Activity - it will be discarded with the method stack or destroyed when the Activity is destroyed.

回到上面的示例,假设 B C 有不同的范围。绑定在 B 中的 Foo @BScoped 。因此,它只应存在于 B 内。但是 D 可以从 C @CScoped Foo $ c>。因此,我们无法再确定 B 是否将 @BScoped Foo 暴露给其子组件-我们已经允许 Foo 逃脱其范围。这是由于不将自己限于有向无环图而带来的处理问题。您可能已经知道,一旦我们禁止循环,计算机科学中的许多问题就变得更容易解决。

Returning to the above example, assume that B and C have different scopes. The Foo bound in B is @BScoped. So it should only live as long as B. But it is possible for D to get the @CScoped Foo from C. So we can no longer ascertain that B is exposing a @BScoped Foo to its subcomponent - we have allowed the possibility of Foo to escape its scope. This is in addition to the processing problems presented by not restricting ourselves to directed acyclic graphs. As you are probably aware, many problems in computer science become easier to solve once we disallow cycles.

事实上,只有当您添加作用域注释,并且在删除它们时消失,并不表示Dagger 2中存在错误或缺少某些缺陷。它仅表示没有作用域注释,因为所有组件实际上都是相等的,因此您仅具有组件层次结构的错觉。再一次,即使您认为您已经通过某种方式将非范围内的组件和范围内的组件组合在一起制成了菱形,也不会真正成为菱形,因为在非范围内的组件中没有真正的层次结构。

The fact that you get the error message for your set up only when you add scope annotations and it disappears when you remove them is not indicative that there is a bug in Dagger 2 or something lacking. It simply means that without scope annotations you only have the illusion of a Component hierarchy since all Components are effectively equal. Again, even if you think you have somehow made a diamond through combination of non-scoped and scoped components, it will not truly be a diamond because there is no real hierarchy in the non-scoped Components.

您建议的体系结构的意图很明确,因为您正在尝试实现的分离。但是,Dagger 2组件用于对生命周期进行分组,而不是对图层进行分组。为了说明这一点,大多数Android应用程序都将具有应用程序范围的依赖项,例如 GSON SharedPreferences 等。这些依赖项通常可以在应用程序的整个生命周期中生存和死亡的元素绑定在 @Singleton 组件的模块集中。您也可以将其命名为 @PerApp @AppScoped -只要保留引用,这实际上并不重要到 Application 子类中的组件。

Your proposed architecture is well-intentioned in that you are trying to achieve separation of layers. However, Dagger 2 components are for grouping lifecycle, not layers. To illustrate, most Android apps will have app-scoped dependencies, such as a GSON, a SharedPreferences etc. These dependencies that live and die together and last for the whole lifecycle of your app are normally bound in the module set for a @Singleton component. You could also call it @PerApp or @AppScoped - it really doesn't matter as long as you retain a reference to the component in your sub-class of Application.

在(DAGger中的DAG),您可以放置​​所需的内容。某些人会创建 @UserScope ,只要应用程序具有登录用户,该持续时间就可以持续。其他人则跳过此步骤,直接转到 @PerActivity @ActivityScoped 组件。 @PerActivity 组件的模块集应绑定具有单个活动生命周期的成员,例如活动的上下文。

Underneath this in your directed acyclic graph (the DAG in DAGger) you can put what you want. Some people make a @UserScope which lasts just as long as the app has a signed-in user. Others skip this step and move straight to @PerActivity or @ActivityScoped components. The module sets for the @PerActivity components should bind members that have the lifecycle of a single activity e.g., the Activity's Context.

此时,最好按功能进行分组,例如。尽管您在此级别的组件将注入来自不同层(模型层和表示层)的依赖关系,但可以通过。另外,您可以将成员分组在同一Java包中,这意味着您可以使用访问修饰符来实现有效的Java项目13:最小化类和成员的可访问性。

At this point it's better to group by functionality like in the Google Android Architecture Blueprint. Although your components at this level will inject dependencies from different layers (the model layer and the presentation layer) these can be separated by judicious use of modules. Additionally, you can group the members will be in the same Java package which means you can use access modifiers to fulfil Effective Java Item 13: Minimise the accessibility of classes and members.

这篇关于依赖于具有不同范围的其他组件的组件(具有不同范围的组件层次结构)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-03 07:54