Dagger @Reusable范围vs @Singleton

phi*_*ilo 38 dependency-injection dagger-2

用户指南:

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

我为什么要用它而不是@Singleton

Jef*_*ica 79

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


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

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

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

妥协在@Reusable绑定中,它具有像@Singleton这样的实例保存属性,但是与范围匹配的@Component规则不同,就像未绑定绑定一样 - 这使您可以更灵活地安装它们.(参见测试.)它们的寿命只有最直接使用它们的最外层组件,并且会机会性地使用来自祖先的实例来进一步保存,但没有双重检查锁定以节省创建成本.最后,最重要的是,它们向您和未来的开发人员发出了关于该课程的使用方式的信号.

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


来自saiedmomen的后续问题: "只要100%清楚,像okhttpclient,retrofit和gson这样的东西应该被声明为@Reusable.对吧?"

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

  • @saiedmomen我不会将`OkHttpClient`声明为可重用。根据文档,最好在整个应用程序中重用单个实例:https://square.github.io/okhttp/3.x/okhttp/okhttp3/OkHttpClient.html (3认同)
  • 杰克·沃顿(Jake Wharton)说,_“ RestAdapter和服务的生成实例(在本例中为MyTaskService)是非常昂贵的对象,应将其用作单例(...),您应仅调用一次restAdapter.create并重复使用相同的对象每次您需要与“ _”交互时,都是MyTaskService的实例。资料来源:/sf/answers/1443890731/ (2认同)
  • 如果我使用@Reusable,基本上,我无法理解我的类实例的生命周期。我有这些问题,1)在任何时间点最多只有一个实例,2)如果不是,它何时创建新对象(通过,已经有一个可用的),3)什么时候会重用现有对象4) 对象何时被垃圾回收。谢谢。 (2认同)