假设我有一个由Dagger 2创建的单例,它实现了接口Foo
和Bar
。代码中有些地方使用Foo
,其他地方使用Bar
,但无论注入哪个接口,我都想要相同的单例。这可能吗?
答案 0 :(得分:4)
是的,这很容易做到,但也很容易做错。诀窍是你需要小心你@Singleton
:Foo,Bar或FooBarImpl。
在Dagger中,任何特定的绑定都可以标记为Singleton,而Dagger干扰的地方是"让我缓存此实例"。像Foo和Bar这样的接口会在@Binds
或@Provides
方法上标记它,像FooBarImpl这样的具体类会在@Provides
方法或具有{的实际类上标记它{1}}注释。
@Inject
这样,无论消费者要求Foo,Bar还是FooBarImpl,他们总是会去Dagger的内部双重检查锁定缓存实例(" DoubleCheck") 。 Foo和Bar也可以标记为@Singleton public class FooBarImpl implements Foo, Bar { /* ... */ }
// in your module:
@Binds Foo bindFoo(FooBarImpl impl);
@Binds Bar bindBar(FooBarImpl impl);
,但它有点浪费,因为内部FooBarImpl提供程序总是会返回相同的实例。无需在Foo Provider或Bar Provider上保留单独的副本。
如果FooBarImpl在外部或在您的控制之外,您可以在@Singleton
方法上标记@Singleton
。
@Provides
假设Foo扩展了Bar,你可以将Bar绑定到Foo。在这里,单例实例保存在Foo提供程序中,注入FooBarImpl将返回新实例,并且Bar的注入将每次都咨询Foo(及其缓存提供程序)。
这听起来严重得多,但是有一些有效的用例:想象一下,如果FooBarImpl是某种类型的CacheImpl,并且你希望Foo和Bar返回一个实例,只有/* not Singleton */ public class FooBarImpl implements Foo, Bar { /* ... */ }
// in your module:
@Binds @Singleton Foo bindFoo(FooBarImpl impl);
@Binds Bar bindBar(Foo foo);
和@Named("accounts") ListeningCache
返回相同的不同实例。
为了完整性:
@Named("accounts") Cache
在这里,Foo和Bar将各自返回一个单独的Singleton实例,并且每次注入FooBarImpl将返回一个新实例。这对于您需要两个或更多对象的用例非常有用,但是当您尝试实现“不太理想”时,请注意不要意外地实施此解决方案。解决方案如上它们看起来非常相似,但行为却截然不同。
答案 1 :(得分:0)
interface FooBar extends Foo, Bar
class FooBarImpl implements FooBar {...}
@SomeScope @Binds FooBar bindsFooBar(impl: FooBarImpl)
@SomeScope @Binds Foo bindsFoo(fooBar: FooBar)
@SomeScope @Binds Bar bindsBar(fooBar: FooBar)