Dagger @Reusable范围vs @Singleton

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

来自User's Guide

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

为什么我会使用它而不是@Singleton

dependency-injection dagger-2
1个回答
71
投票

如果您依赖单身行为和保证,请使用@Singleton。如果出于性能原因,对象只是@Singleton,请使用@Reusable。


与@Singleton绑定相比,@ Reusable绑定与未绑定绑定有更多共同点:你告诉Dagger你可以创建一个全新的对象,但如果已经创建了一个方便的对象,那么Dagger可能会使用那个。相比之下,@ Singleton对象保证您将始终收到相同的实例,这可能会更加昂贵。

一般来说,Dagger和DI更喜欢没有对象的对象:创建一个新对象是保持状态紧密包含的好方法,并且允许在依赖对象可以时对对象进行垃圾收集。 Dagger显示了一些内置的首选项:在Dagger中,未编组的对象可以混合到任何组件或模块中,无论组件是否是范围注释的。这种类型的无范围绑定对于无状态对象(如可注入(可模拟)实用程序类)以及strategycommand和其他多态性behavioral design patterns的实现也很有用:对象应该全局绑定并注入以进行测试/覆盖,但实例不保留任何国家和短命或一次性。

但是,在Android和其他性能和内存受限的环境中,it goes against performance recommendations to create a lot of temporary objects,因为实例创建和垃圾收集都是比桌面虚拟机更昂贵的进程。这导致了标记对象@Singleton的实用解决方案,并不是因为始终获得相同的实例,而只是为了保存实例是很重要的。这有效,但在语义上很弱,并且还具有内存和速度含义:只要您的应用程序存在,您的短期util或strategy模式对象现在必须存在,并且必须通过双重检查锁定来访问,否则您风险违反“仅一个实例”@Singleton保证(这里不必要)。这可能是增加内存使用和同步开销的原因。

妥协是在@Reusable绑定中,它具有像@Singleton这样的实例保存属性,但是就像未绑定的绑定一样是excepted from the scope-matching @Component rule - 这使您可以更灵活地安装它们。 (参见tests。)它们的寿命只有最直接使用它们的最外层组件,并且会机会性地使用来自祖先的实例来进一步保存,但是without double-checked locking可以节省创建成本。最后,最重要的是,它们向您和未来的开发人员发出了关于该课程的使用方式的信号。

简而言之,@ Singleton可以工作,但如果整个点是性能而不是对象生命周期,@ Reusable有一些明显的性能优势。


来自saiedmomen的后续问题:“只要100%清除okhttpclient,retrofit和gson这样的东西就应该声明为@Reusable。对吧?”

是的,总的来说,我认为将无状态实用程序和库声明为@Reusable会很好。但是,如果他们秘密地保留一些类似状态的处理连接限制或在所有消费者之间进行批处理 - 你可能想让它们成为@Singleton,并且如果它们很少使用来自长寿命组件,那么使它们无范围可能仍然是有意义的。他们可以被垃圾收集。在这里制作适用于所有案例和库的一般声明真的很难:您必须根据库功能,内存权重,实例化成本和所涉及对象的预期寿命来决定。

正如manage its own connection and thread pools per instance在评论中所指出的那样,OkHttpClient尤其是Wyko;这将使它成为@Singleton优于@Reusable的好候选人。谢谢Wyko!

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