Dagger @Reusable 作用域与 @Singleton [英] Dagger @Reusable scope vs @Singleton

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

问题描述

来自用户指南:

有时你想限制@Inject-constructed 的次数类被实例化或@Provides 方法被调用,但你没有需要保证在执行期间使用完全相同的实例任何特定组件或子组件的生命周期.

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.

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

Why would I use that instead of @Singleton?

推荐答案

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

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

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

@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.

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

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.

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

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.

妥协在于@Reusable 绑定,它具有像@Singleton 这样的实例保存属性,但从范围匹配的@Component 规则中排除,就像非范围绑定一样——这让你在安装它们的位置上有更大的灵活性.(参见 tests.)它们的生命周期仅与直接使用它们的最外层组件一样长,并且会机会性地使用来自祖先的实例来进一步保存,但是 无需双重检查创建锁定以节省成本(因此,@Reusable 对象的多个实例可能同时存在于您的对象图中,尤其是当它们同时在多个线程上被请求时.)最后,也是最重要的是,它们向您和未来的开发人员发出了关于类的使用方式.

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. (Consequently, several instances of a @Reusable object may exist simultaneously in your object graph, particularly if they were requested on multiple threads at the same time.) Finally, and most importantly, they're a signal to you and future developers about the way the class is intended to be used.

虽然成本较低,但不是零:如Ron Shapiro 在 Medium 上评论,可重用的成本与单例相同.它保存同步,但它仍然强制在应用程序启动时加载额外的类.这里真正的建议是永远范围,除非您已经进行了分析并且您已经看到了通过范围界定的性能改进."您必须自己评估速度和内存效果:@Reusable 是工具箱中的另一个有用工具,但这并不意味着它总是或显然是一个不错的选择.

Though the cost is lower, it's not zero: As Ron Shapiro notes on Medium, "Reusable has many of the same costs as Singleton. It saves synchronization, but it still forces extra classes to be loaded at app startup. The real suggestion here is to never scope unless you’ve profiled and you’ve seen a performance improvement by scoping." You'll have to evaluate the speed and memory effects yourself: @Reusable is another useful tool in the toolbox, but that doesn't mean it's always or obviously a good choice.

简而言之,@Singleton 可以工作,但如果重点是性能而不是对象生命周期,@Reusable 具有一些明显的性能优势.不要忘记在标记实例之前和之后测量性能 @Reusable,以确保 @Reusable 确实对您的用例有益.

In short, @Singleton would work, but @Reusable has some distinct performance advantages if the whole point is performance instead of object lifecycle. Don't forget to measure performance before and after you mark an instance @Reusable, to make sure @Reusable is really a benefit for your use case.

来自 saiedmomen 的后续问题:只是为了 100% 清楚事情像 okhttpclient 一样,retrofit 和 gson 应该声明为@Reusable.对吧??"

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

是的,总的来说,我认为将无状态实用程序和库声明为@Reusable会很好.然而,如果它们秘密地保持某种状态——比如处理连接限制或在所有消费者之间进行批处理——你可能想让它们@Singleton,并且如果它们从长期存在的组件 使它们无作用域可能仍然有意义,以便它们可以被垃圾收集.在这里很难做出适用于所有案例和库的一般性声明:您必须根据库功能、内存权重、实例化成本和所涉及对象的预期寿命做出决定.

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 特别是 管理自己的连接和线程池实例,正如Wyko 在评论中指出的,Albert Vila Calvo 同样指出Retrofit 的预期单例行为.这将使 @Singleton 成为 @Reusable 的优秀候选者.感谢 Wyko 和 Albert!

OkHttpClient in particular does manage its own connection and thread pools per instance, as Wyko points out in the comments, and Albert Vila Calvo likewise notes Retrofit's intended-singleton behavior. That would make those good candidates for @Singleton over @Reusable. Thanks Wyko and Albert!

这篇关于Dagger @Reusable 作用域与 @Singleton的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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