android - Dagger2 范围,每个组件的实例

标签 android dagger-2

我正在寻找有关 Android 中 Dagger 2 范围的快速确认。

在许多在线资源中,您会发现 @ActivityScope@FragmentScope 被添加到为 Activity 和 fragment 提供绑定(bind)的组件中。

我想确认一下,这意味着所有 Activity/所有 fragment 将分别有 1 个实例。
也就是说,比方说,如果两个 Activity 使用同一个组件来接收来自同一个组件的依赖项,该组件用范围“Activity”进行注释,则两个 Activity 将接收相同的实例(就像单例注释一样有效)。

因此,在那种情况下,使用@ActivityScope 和@FragmentScope 注释只会对区分 Activity 与 fragment 之间的依赖生命周期有用。
因此,如果我需要一个依赖对象,并且在两个 Activity 中需要一个单独的实例,我应该明确地确定它们的范围(例如@LoginActivityScope)。

你能确认这个假设是正确的吗?

编辑:

阅读有关子组件的文档,让我有点困惑:

No subcomponent may be associated with the same scope as any ancestor component, although two subcomponents that are not mutually reachable can be associated with the same scope because there is no ambiguity about where to store the scoped objects. (The two subcomponents effectively have different scope instances even if they use the same scope annotation.)

这似乎假设如果您有多个组件使用相同的注释,当相同的 scope 注释用于不同的组件时,它确实会创建一个单独的实例。

我发现对于 scope instance 指的是什么有点不清楚。这其实是指绑定(bind)?
这是否仅适用于子组件?

一些关于作用域与依赖实例(绑定(bind))的说明会很有帮助。

最佳答案

作用域组件将在第一次使用时创建一个作用域对象,然后它会保留它。如果您第二次创建相同的组件,它也会在第一次使用时创建作用域对象。组件只是对象,它们不持有任何全局(静态)状态,因此如果您重新创建组件,您将重新创建它的所有内容。

val component = DaggerScopedComponent.create()
component.getScopedObject() === component.getScopedObject() // always the same object!

// never the same object! two different components, albeit same scope
DaggerScopedComponent.create().getScopedObject() != DaggerScopedComponent.create().getScopedObject() 

Dagger 生成代码,因此我邀请您创建一个简单 示例并查看代码。例如上面的示例应该很容易阅读

@Singleton class Foo @Inject constructor()

@Singleton @Component interface ScopedComponent {
  fun getScopedObject() : Foo
}

如果您有一个作用域组件比其子作用域生命周期更长,那么您必须保留对该组件的引用并重用它。通常的做法是在需要时在其共享生命周期(Application、Activity、Fragment)的对象中保留对组件的引用。

假设我们在上面的例子中添加了一个子组件

@Singleton class Foo @Inject constructor()

@Singleton @Component interface ScopedComponent {
    fun getScopedObject() : Foo

    fun subComponent() : SubComponent
}


@Other @Subcomponent interface SubComponent {
    fun getScopedObject() : Foo
}

@Scope
@MustBeDocumented
annotation class Other

只要我们使用相同的 @Singleton 组件,我们将始终获得相同的 @Singleton 作用域对象。

// Subcomponents will have the same object as the parent component
component.subComponent().getScopedObject() === component.getScopedObject()

// as well as different Subcomponents
component.subComponent().getScopedObject() === component.subComponent().getScopedObject()

现在回答你的问题......


I would like to have some confirmation that this implies that there will be 1 instance for all activities / all fragments respectively. That is, if, say, two activities use the same component for receiving dependencies from the same component annotated with scope 'Activity', both activities will receive the same instance (like singleton annotation would work).

如上所示,无论是哪个子组件,相同 作用域组件提供的任何作用域对象都是相同的。如果您创建两个 @ActivityScope MyActivityComponent,那么 @ActivityScoped 范围内的所有内容都将每个组件创建一次

如果您希望在 Activity 的组件之间共享对象,您必须使用更高范围并保持对已创建组件的引用。


So in that case having @ActivityScope and @FragmentScope annotations would only be useful to segregate between dependency lifetimes between activities versus fragments.

不,因为您可以有一个 @ActivityScope FooActivityComponent 和一个 ActivityScope BarActivityComponent,它们永远不会共享一个 @ActivityScope 类FooBar 对象,将为每个 @ActivityScope 范围内的组件创建一次。

So if I would need a dependency object for which I need a separate instance in two activities, I should scope them explicitly (e.g. @LoginActivityScope).

@ActivityScope FooActivityComponent@ActivityScope LoginActivityComponent永远共享任何 @ActivityScope 作用域对象。您可以在此处使用相同的范围。如果您愿意,您也可以创建不同的范围,但这对此处没有影响。


This would seem to assume that if you have multiple components using the same annotation, it does create a separate instance when the same scope annotation is used for different components.

是的

I find it a bit unclear as to what a scope instance refers to. This actually refers to the binding? Does this only apply to subcomponents?

您不能拥有像 Singleton > ActivityScope > ActivityScope 这样的组件层次结构,因为这些重复的范围将无法知道 @ActivityScope 范围对象是否是其中的一部分第一个或第二个。

您可以在同一范围内拥有两个不同的组件,两个子组件都属于同一父级(它们不能“相互访问”),并且任何 @ActivityScope 范围内的对象都将是后者 @ActivityScope 作用域组件。每个组件都有一个作用域对象(如上例所示),并且可以有两个或更多组件实例。

  • 单例 > ActivityScope FooComponent
  • 单例 > ActivityScope BarComponent

我建议您暂时忘掉 Android,只使用 Dagger 和生成的代码,就像上面显示的代码一样。恕我直言,这是弄清楚事情如何运作的最快方法,一旦“魔法”消失,您就会发现它只是一个包含一些变量的 POJO。

关于android - Dagger2 范围,每个组件的实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55505015/

相关文章:

java - wifi只能连接一次吗?

android - lateinit property dispatchingAndroidInjector 还没有初始化

android - Dagger 2注入(inject)相同对象类型的多个实例

android - PagerAdapter 内的 RecyclerView 不更新内容

java - 单击按钮时 Android 崩溃。

java - Dagger 2循环注入(inject)

android - 来自多个组件的现场注入(inject)

android - 自动生成的代码(如Dagger2)在持续集成中存在严重问题

java - Android 中使用 AES 128 算法进行文本加密

android - 如何在我的 Android 应用程序本身中使用 Mockito?我收到 Hamcrest 依赖冲突,当它仅用于测试时我没有收到