匕首@Reusable范围vs @Singleton [英] Dagger @Reusable scope vs @Singleton

查看:147
本文介绍了匕首@Reusable范围vs @Singleton的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

用户指南


有时您想限制@Inject构造的
类被实例化或调用@Provides方法的次数,但是您不必
需要保证在任何特定组件或子组件的
生存期内都使用了完全相同的实例。


为什么我用它代替 @Singleton

解决方案

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






@Reusable绑定有很多共同点使用@Singleton绑定之外的非作用域绑定:您是在告诉Dagger您可以创建一个全新的对象,但是如果已经创建了一个方便的对象,则Dagger 可以使用该对象。相比之下,您将总是总是使用的@Singleton对象 guarantee 会收到 same 实例,这可能会更昂贵。



通常,Dagger和DI更喜欢不受作用域的对象:创建新对象是保持状态紧密包含的好方法,并且允许在依赖对象被回收时立即进行垃圾收集。对象可以。 Dagger显示了一些内置的首选项:在Dagger中,无作用域的对象可以混入任何组件或模块中,而不管组件是否具有范围注释。这种类型的无作用域绑定也可用于无状态对象,例如可注入(可模拟)实用程序类和策略,命令,以及其他多态的行为 设计模式:对象应该在全球范围内绑定并注入以进行测试/替代,但是实例不保留任何状态,并且是短暂的或可丢弃的。



但是,在Android和其他性能方面,受内存限制的环境,它违反了性能建议,无法创建许多临时对象,因为实例创建和垃圾回收a与台式机VM相比,这两个过程都更昂贵。这导致了一种实用的标记对象@Singleton的解决方案,这不是因为始终获取相同的实例很重要,而只是保存实例。这可行,但在语义上很弱,并且还具有内存和速度方面的影响:只要应用程序存在,您的短暂util或策略模式对象现在就必须存在,并且必须通过double访问-检查的锁定,否则可能会违反仅一个实例 @Singleton保证的风险(此处不必要)。这可能是增加内存使用量和同步开销的原因。



折衷之处在于@Reusable绑定,该绑定具有实例保存属性,例如@Singleton,但除了范围匹配@Component规则就像无作用域的绑定一样,可以为您提供更多的安装位置灵活性。 (请参见测试。)它们的寿命仅与直接使用它们的最外层组件一样长,并且有机会使用祖先的实例进行进一步保存,但是无需仔细检查锁定即可节省创建成本。最后,最重要的是,它们向您和未来的开发人员发出信号,告知您打算使用该类的方式。



简而言之,@ Singleton可以工作,但是@Reusable在性能方面而不是对象生命周期方面具有明显的性能优势。






来自 saiedmomen 的问题:应该声明okhttpclient,retrofit和gson等100%清晰的东西@Reusable。对吗?



是的,一般来说,我认为将无状态实用程序和库声明为 @Reusable 。但是,如果它们秘密地保持某种状态(例如处理连接限制或在所有使用者之间进行批量处理),则可能要使它们成为 @Singleton ,并且如果它们被使用得非常频繁

在这里很难做出一个适用于所有情况和库的一般声明:您必须根据库功能,内存权重,实例化成本以及所涉及对象的预期寿命来进行决定。



OkHttpClient特别会管理自己的连接和每个实例的线程池,如 Wyko 在注释中指出的那样;相对于 @Reusable ,它更适合 @Singleton 。谢谢Wyko!


From the User's Guide:

Sometimes you want to limit the number of times an @Inject-constructed class is instantiated or a @Provides method is called, but you don’t need to guarantee that the exact same instance is used during the lifetime of any particular component or subcomponent.

Why would I use that instead of @Singleton?

解决方案

Use @Singleton if you rely on singleton behavior and guarantees. Use @Reusable if an object would only be a @Singleton for performance reasons.


@Reusable bindings have much more in common with unscoped bindings than @Singleton bindings: You're telling Dagger that you'd be fine creating a brand-new object, but if there's a convenient object already created then Dagger may use that one. In contrast, @Singleton objects guarantee that you will always receive the same instance, which can be much more expensive to enforce.

In general, Dagger and DI prefer unscoped objects: Creating a new object is a great way to keep state tightly-contained, and allows for objects to be garbage-collected as soon as the dependent object can. Dagger shows some of this preference built-in: In Dagger unscoped objects can be mixed in to any component or module, regardless of whether the component is scope-annotated. This type of unscoped binding is also useful for stateless objects like injectable (mockable) utility classes and implementations of strategy, command, and other polymorphic behavioral design patterns: The objects should be bound globally and injected for testing/overrides, but instances don't keep any state and short-lived or disposable.

However, in Android and other performance- and memory-constrained environments, it goes against performance recommendations to create a lot of temporary objects, because instance creation and garbage collection are both more-expensive processes than on desktop VMs. This leads to the pragmatic solution of marking an object @Singleton, not because it's important to always get the same instance, but just to conserve instances. This works, but is semantically-weak, and also has memory and speed implications: Your short-lived util or strategy pattern object now has to exist as long as your application exists, and must be accessed through double-checked locking, or else you risk violating the "one instance only" @Singleton guarantee (that is unnecessary here). This can be a source of increased memory usage and synchronization overhead.

The compromise is in @Reusable bindings, which have instance-conserving properties like @Singleton but are excepted from the scope-matching @Component rule just like unscoped bindings—which gives you more flexibility about where you install them. (See tests.) They have a lifespan only as long as the outermost component that uses them directly, and will opportunistically use an instance from an ancestor to conserve further, but without double-checked locking to save on creation costs. Finally, and most importantly, they're a signal to you and future developers about the way the class is intended to be used.

In short, @Singleton would work, but @Reusable has some distinct performance advantages if the whole point is performance instead of object lifecycle.


Follow-up question from saiedmomen: "Just to be 100% clear things like okhttpclient, retrofit and gson should be declared @Reusable. right??"

Yes, in general I think it'd be good to declare stateless utilities and libraries as @Reusable. However, if they secretly keep some state—like handling connection limits or batching across all consumers—you might want to make them @Singleton, and if they are used very infrequently from a long-lived component it might still make sense to make them scopeless so they can be garbage-collected. It's really hard to make a general statement here that works for all cases and libraries: You'll have to decide based on library functionality, memory weight, instantiation cost, and expected lifespan of the objects involved.

OkHttpClient in particular does manage its own connection and thread pools per instance, as Wyko points out in the comments; that would make it a good candidate for @Singleton over @Reusable. Thanks Wyko!

这篇关于匕首@Reusable范围vs @Singleton的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆