我正在尝试理解Dagger @Reusable
范围的使用。从文档中我可以理解的是,如果提供程序的作用域为@Singleton
或任何其他自定义作用域,则首先创建对象,然后在组件的整个生命周期中对其进行高速缓存。因此,对于并不总是需要相同实例或较少使用的对象,这种方法最终会浪费内存。
但是如果我们选择一个非范围的提供者,每次它都会创建一个新实例,并且由于对象实例化很昂贵,特别是在Android等环境中,分配可能很昂贵,这可能会导致性能问题。
@Reusable
范围位于无范围和范围实例之间。
从文档
有时您希望限制实例化@Inject构造的类或调用@Provides方法的次数,但您不需要保证在任何特定组件的生命周期内使用完全相同的实例或子组件
它是如何工作的?假设我的AppComponent
中有一个可重用的提供程序,它不会总是给我相同的实例吗?
如果我在任何Subcomponent
中注入相同的依赖项,我会获得相同的实例吗?什么时候将为GC释放缓存的对象?
我尝试了一个示例,在我的@Reusable
模块中创建了一个AppComponent
对象,并从我的子组件中注入了该对象。
我能看到的是它的行为与@Singleton
完全相同。
我们可以从@Reusable
获得哪些性能改进?
我们应该选择哪些可能的用例@Reusable
?
将所有无状态对象(无论我们得到相同的实例都无关紧要)(例如Util类,Gson,Glide等)作为@Reusable
的范围,这是一个好主意吗?
答案 0 :(得分:5)
我想指出,自{v1.13}起@Reusable
仍处于测试阶段,因此可能会再次更改或删除。
tl; dr 它的行为类似于变量范围,但不保证在任何给定时间都有单个实例。
它是如何工作的?假设我的AppComponent中有一个可重用的提供程序,它不会总是给我相同的实例吗?
Javadoc在这个问题上非常清楚:
一个范围,指示绑定返回的对象可能(但可能不会)重用。
@Reusable在您想要限制类型的条款数量时很有用,但是没有特定的生命周期,只有一个实例。
它没有提供有关它如何工作的任何信息,你不应该依赖任何可能的实现,因为它们可能会改变,特别是当它仍然在@Beta
时。
假设@Reusable
可以用于可以多次存在的对象,但是多个对象的实例化可能会更昂贵,因此重新使用对象是有意义的。
虽然实施可能会改变,但预期用途不会改变。因此,如果您决定使用@Reusable
,那么您应该确保您拥有一个,两个或多个对象实例,无论它们是否被缓存。< / p>
哪些是可能的用例,我们应该更喜欢@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
的内部运作方式,我不会感到惊讶,但现在知道它的作用范围可能有助于决定何时使用它。