Dagger2范围,每个组件的实例

问题描述 投票:4回答:1

我正在寻找关于Android中Dagger 2示波器的快速确认。

在许多在线资源中,您会发现@ActivityScope@FragmentScope被添加到为活动和片段提供绑定的组件中。

我想得到一些确认,这意味着所有活动/所有片段将分别有1个实例。 也就是说,如果两个活动使用相同的组件来接收来自使用范围“活动”注释的同一组件的依赖关系,则两个活动都将接收相同的实例(就像单例注释一样)。

因此,在这种情况下,使用@ActivityScope和@FragmentScope注释只能在活动与片段之间的依赖生存期之间进行隔离。 因此,如果我需要一个依赖项对象,我需要在两个活动中使用一个单独的实例,我应该明确地将它们作为范围(例如@LoginActivityScope)。

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

编辑:

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

虽然两个不可相互可达的子组件可以与相同的范围相关联,但是没有任何子组件可以与任何祖先组件关联相同的范围,因为没有关于存储范围对象的位置的歧义。 (这两个子组件实际上具有不同的范围实例,即使它们使用相同的范围注释。)

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

我发现scope instance指的是什么有点不清楚。这实际上是指绑定? 这仅适用于子组件吗?

关于范围与依赖实例(绑定)的一些说明将非常有用。

android dagger-2
1个回答
1
投票

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

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
}

如果您的作用域组件的寿命比其子范围长,那么您必须保留对该组件的引用并重用它。通常的做法是在需要时保持对象的组件的引用,该组件的生命周期(应用程序,活动,片段)。

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

@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()

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


我想得到一些确认,这意味着所有活动/所有片段将分别有1个实例。也就是说,如果两个活动使用相同的组件来接收来自使用范围“活动”注释的同一组件的依赖关系,则两个活动都将接收相同的实例(就像单例注释一样)。

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

如果希望在活动组件之间共享对象,则必须使用更高的范围并保留对创建的组件的引用。


因此,在这种情况下,使用@ActivityScope和@FragmentScope注释只能在活动与片段之间的依赖生存期之间进行隔离。

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

因此,如果我需要一个依赖项对象,我需要在两个活动中使用一个单独的实例,我应该明确地将它们作为范围(例如@LoginActivityScope)。

@ActivityScope FooActivityComponent@ActivityScope LoginActivityComponent永远不会分享任何@ActivityScope范围的对象。您可以在此处使用相同的范围。如果你愿意,你也可以创建一个不同的范围,但这里没有任何区别。


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

是的

我发现范围实例所指的内容有点不清楚。这实际上是指绑定?这仅适用于子组件吗?

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

您可以拥有相同范围的两个不同组件,即同一父组件的两个子组件(它们不能彼此“到达”),并且任何@ActivityScope范围对象都将是后一个@ActivityScope范围组件的一部分。每个组件都有一个范围对象(如上例所示),您可以有两个组件实例或更多。

  • Singleton > ActivityScope FooComponent
  • Singleton > ActivityScope BarComponent

我建议你稍微忘掉Android,然后只使用Dagger和生成的代码,就像上面显示的代码一样。这是恕我直言,这是了解事情如何运作的最快方法,一旦“神奇”消失,你会发现它只是一个带有一些变量的POJO。

© www.soinside.com 2019 - 2024. All rights reserved.