【问题标题】:What is the use of @Reusable scope in Dagger 2Dagger 2中@Reusable作用域的用途是什么
【发布时间】:2017-12-10 18:21:14
【问题描述】:

我正在尝试了解 Dagger 的 @Reusable 范围的使用。从文档中我可以理解的是,如果提供者的范围是 @Singleton 或任何其他自定义范围,那么将首先创建对象,然后在组件的整个生命周期内缓存该对象。因此,对于并不总是需要是同一个实例或不经常使用的对象,这种方法最终会浪费内存。

但是,如果我们选择一个非作用域的提供者,每次它都会创建一个新实例,而且由于对象实例化成本很高,尤其是在 Android 等环境中,分配可能很昂贵,这可能会导致性能问题。

@Reusable 作用域介于无作用域和作用域实例之间。 来自文档

有时您希望限制实例化 @Inject 构造的类或调用 @Provides 方法的次数,但您不需要保证在任何特定组件的生命周期内使用完全相同的实例或子组件

它是如何工作的?假设我的AppComponent 中有一个可重用的提供程序,它不会总是给我相同的实例吗?

如果我在任何Subcomponent 中注入相同的依赖项,我会得到相同的实例吗?缓存的对象何时会被释放以进行 GC?

我尝试了一个示例,在我的 AppComponent 模块中创建了一个 @Reusable 对象,并从我的子组件中注入了它。
我可以看到它的行为与@Singleton 完全一样。

我们可以通过@Reusable 实现哪些性能改进?

我们应该更喜欢@Reusable 的哪些可能用例?

将 Util 类、Gson、Glide 等所有无状态对象(无论我们是否获得相同的实例)设置为@Reusable 的范围是个好主意吗?

【问题讨论】:

  • 将此标记为 Dagger @Reusable scope vs @Singleton 的副本:我认为它回答了您的大部分子问题,但可能无法全部回答。如果您愿意保留这个问题,请告诉我,但我认为将问题/答案结合起来是有意义的。

标签: android dagger-2 dagger


【解决方案1】:

我想指出,@Reusable 从 v2.13 开始仍处于测试阶段,因此可能会再次更改或删除。

tl;dr 它的行为就像一个变量范围,但不能保证在任何给定时间都有一个实例。

它是如何工作的?假设我的 AppComponent 中有一个可重用的提供程序,它不会总是给我相同的实例吗?

Javadoc 在该主题上非常(不)清楚:

表示绑定返回的对象可能(但可能不会)重用的范围。

@Reusable 当您想限制一种类型的规定数量时很有用,但没有特定的生命周期必须只有一个实例。

它没有提供任何关于它如何在幕后工作的信息,你不应该依赖任何潜在的实现,因为它们可能会改变,尤其是当它仍在 @Beta 中时。

假设@Reusable 可用于可多次存在的对象,但其中多个对象的实例化成本可能更高,因此重用该对象是有意义的。

虽然实施可能会改变,但预期用途不会改变。因此,如果您决定使用 @Reusable,您应该确保您的对象有一个、两个或多个实例,无论它们在哪里或是否被缓存。

我们应该更喜欢@Reusable 的哪些可能用例?

将 Util 类、Gson、Glide 等所有无状态对象(无论我们是否获得相同的实例)作为@Reusable 的范围是一个好主意吗?

如前所述,您应该使用它来重用对象,正如其名称所暗示的那样。 Gson 是一个相当糟糕的例子,因为它使用了相当多的反射并且它的实例化非常昂贵,它可能应该是@Singleton。 Glide 也不是一个很好的例子,因为它无论如何都会在内部使用 Singleton 模式。

@Reusable 相对于@Singleton 的一个好处是您无需声明作用域或组件之间的层次结构。将对象限定为@Singleton 将意味着您的 AppComponent 将在其整个生命周期内保存该对象,而使用@Reusable 时,该对象可能只会在依赖关系树下的子组件中创建并与它一起再次销毁。
我不会将它用于依赖项很少的对象,因为它们可以很容易地创建,但将它用于不包含任何状态且需要更多设置的对象。

但是它是如何工作的呢?

可重用是一种@Scope,它得到了一些特殊处理。你可以看到commit where it was added

作为一个范围,带有@Reusable 注释的对象将被保存在一个组件中。你可以看看第一个单元测试。它验证子组件是否将重用其父提供者(如果可用)。这就是您提到的行为以及为什么它似乎对@Singleton 没有影响。

与普通作用域的区别在于使用的Provider@Reusable 不使用ScopedProvider,而是使用SimpleLazilyInitializedProvider。它在创建对象时省略了synchronized 关键字,这可能会稍微提高性能,但解​​释了为什么没有特定的生命周期必须只有一个实例

如果他们将来改变 @Reusable 的内部工作原理,我不会感到惊讶,但现在知道它的作用域可能有助于决定何时使用它。

【讨论】:

  • 感谢您的详细解释!
  • 今天 Dagger 使用 SingleCheck 来提供可重用的服务。在我认为如果应用程序组件提供可重用的项目并且经过一些使用并且没有实际引用它只是清理它们(例如 WeakReference)之前。但是现在我看到 Dagger 缓存了这些项目并且永远不会清理它们。这意味着提供的带有 Reusable 注释的项目将被缓存,直到 Dagger 组件被销毁。如果您需要一个缓存行为,直到在不同的地方使用组件,您可以提供没有任何范围的项目并将其缓存在模块中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-30
  • 2017-01-01
  • 1970-01-01
相关资源
最近更新 更多