我试图了解Dagger的@Reusable
范围的使用。从文档中,我可以理解的是,如果提供程序的范围是@Singleton
或任何其他自定义范围,则将首先创建对象,然后在组件的整个生命周期内对其进行缓存。因此,对于并非总是需要相同实例或不经常使用的对象,这种方法最终会浪费内存。
但是,如果我们选择一个非作用域的提供程序,则每次创建一个新实例时,由于对象实例化是昂贵的,尤其是在Android这样的环境中(分配可能是昂贵的),这可能导致性能问题。@Reusable
范围位于No-scope和Scoped实例之间。
从文档中
究竟如何运作?假设我的AppComponent
中有一个可重用的提供程序,难道它不总是给我相同的实例吗?
如果我在任何Subcomponent
中注入(inject)相同的依赖项,是否会得到相同的实例?何时才将缓存的对象释放给GC?
我尝试了一个示例,在我的@Reusable
模块中创建了一个AppComponent
对象,并将其从我的子组件中注入(inject)。
我看到的是它的行为与@Singleton
完全相同。
从@Reusable
可以实现哪些性能改进?
我们应该首选@Reusable
的可能用例有哪些?
将所有无状态对象(无论是否获得相同的实例)(如Util类,Gson,Glide等)的范围限定为@Reusable
是一个好主意吗?
最佳答案
我想指出的是,从v2.13开始,@Reusable
仍处于beta中,因此可能会再次更改或删除它。
tl; dr 它的行为就像变量作用域,不能保证在任何给定时间只有一个实例。
Javadoc在该主题上非常(不清楚):
它没有提供任何有关其幕后工作方式的信息,并且您不应该依赖任何可能的实现,因为它们可能会发生变化,尤其是当它仍在@Beta
中时。
假设@Reusable
可以用于可以多次存在的对象,但是多个对象的实例化可能会花费更多,因此有意义的是可以重用该对象。
虽然实现可能会更改,但预期的用途不会改变。因此,如果您决定使用@Reusable
,则应来确保您是否拥有对象的一个,两个或多个实例,无论它们在何处或是否被缓存都无关紧要。
如前所述,您应该使用它,就像名称所暗示的那样,可以重用一个对象。 Gson是一个非常糟糕的示例,因为它使用了很多反射,并且其实例化非常昂贵,因此它可能应该是@Singleton
。 Glide也不是一个很好的例子,因为无论如何它都会在内部使用Singleton模式。@Reusable
优于@Singleton
的一个好处是,您无需声明作用域或组件之间的层次结构。将对象设置为@Singleton
意味着您的AppComponent将在整个生命周期内保留该对象,而使用@Reusable
则只能在依赖项树的整个子级中的子组件中创建该对象,并再次将其销毁。
我不会将其用于具有很少依赖性的对象,因为它们可以很容易地创建,但不会将其用于不持有任何状态并且需要更多设置的对象。
但是它是如何工作的呢?
可重用是一种经过特殊处理的@Scope
。您可以看到commit where it was added。
作为范围,使用@Reusable
注释的对象将保存在组件内。您可以看一下第一个单元测试。它验证子组件将重用其父级的提供者(如果有)。这是您提到的行为,为什么它与@Singleton
没什么关系。
与正常作用域的区别在于所使用的Provider
。代替使用 ScopedProvider
,@Reusable
使用 SimpleLazilyInitializedProvider
。它在创建对象时省略了synchronized
关键字,这可能会略微提高性能,但解释了为什么没有特定生存期的情况,因此只能有一个实例。
如果他们将来更改@Reusable
的内部工作原理,我不会感到惊讶,但是就目前而言,知道它的作用范围很广,可能有助于决定何时使用它。
关于android - Dagger 2中@Reusable范围的用途是什么,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47742002/