我可能错过了一些东西,但我认为像@Singleton这样的Scopes用来定义“范围生命周期”。
我在Android应用中使用Dagger 2(但我认为这个问题与Android无关)。
我有1个模块:
@Module public class MailModule {
@Singleton @Provides public AccountManager providesAccountManager() {
return new AccountManager();
}
@Singleton @Provides public MailProvider providesMailProvider(AccountManager accountManager) {
return new MailProvider(accountManager);
}
}
我有两个不同的组件@Singleton
范围:
@Singleton
@Component(modules = MailModule.class)
public interface LoginComponent {
public LoginPresenter presenter();
}
@Singleton
@Component(
modules = MailModule.class
)
public interface MenuComponent {
MenuPresenter presenter();
}
MenuPresenter
和LoginPresenter
都有一个@Inject
构造函数。虽然MenuPresenter期望MailProvider
作为参数,但LoginPresenter需要AccountManager
:
@Inject public MenuPresenter(MailProvider mailProvider) { ... }
@Inject public LoginPresenter(AccountManager accountManager) { ... }
但每次我使用这些组件创建MenuPresenter
或LoginPresenter
时,我都会获得MailProvider
和AccountManager
的全新实例。我认为它们属于同一范围,因此应该是单一的(在同一范围内)。
我是否完全理解了一些错误。如何在匕首2中为多个组件定义真正的单例?
答案 0 :(得分:50)
我认为LoginComponent
和MenuComponent
是分开使用的,例如在LoginActivity
和MenuActivity
中。每个组件都内置在Activity.onCreate
中。如果是这样,每次创建新活动时,都会重新创建组件,模块和依赖项,而与它们所绑定的范围无关。因此,您每次都会获得MainProvider
和AccountManager
的新实例。
MenuActivity
和LoginActivity
具有单独的活动周期,因此来自MailModule
的依赖关系不能在这两者中都是单例。您需要的是声明具有@Singleton
范围的根组件(例如在Application子类中),make MenuComponent
和LoginComponent
依赖于它。活动级别组件不能是@Singleton作用域,最好使用@Scope
注释创建自己的作用域,例如:
@Retention(RetentionPolicy.RUNTIME)
@Scope
public @interface MenuScope {
}
或者你可以让他们不受约束。
关于这里的范围,从最初Dagger 2 proposal开始简要说明:
@Singleton @Component(modules = {…}) public interface ApplicationComponent {}
该声明使匕首能够强制执行以下约束:
- 给定组件可能只具有未作用域或声明范围的绑定(包括类的范围注释)。 即组件不能代表两个范围。没有范围时 列出的,绑定可能只是未绑定。
- 作用域组件可能只有一个作用域依赖项。这是强制两个组件都不声明它们的机制 自己的范围绑定。例如。每个都有两个Singleton组件 他们自己的@Singleton Cache将被破坏。
- 组件的范围不得出现在任何传递依赖项中。例如:SessionScoped - > RequestScoped - > SessionScoped 没有任何意义,是一个错误。
- @Singleton受到特殊处理,因为它不能有任何作用域依赖项。每个人都希望Singleton成为“根”。
这种规则组合的目标是在范围时强制执行 应用时,组件由我们使用的相同结构组成 拥有Dagger 1.0 plus()'d ObjectGraphs,但有能力 拥有所有绑定及其范围的静态知识。放在 换句话说,当应用范围时,这限制了图形 可以只构建那些可以正确构造的那些。
从我自己的实践来看,更清楚的是根本不使用@Singleton
。而不是那样,我使用@ApplicationScope
。它用于在整个应用程序中定义单例,并且没有@Singleton
所具有的额外限制。
希望能帮到你:)。快速理解是非常棘手的,需要时间,对我来说至少是这样。
答案 1 :(得分:7)
您可以执行以下操作来为多个组件定义实际单例。我假设@ApplicationScoped
和@ActivityScoped
是不同的范围。
@Module public class MailModule {
@Provides @ApplicationScoped
public AccountManager providesAccountManager() {
return new AccountManager();
}
@Provides @ApplicationScoped
public MailProvider providesMailProvider(AccountManager accountManager) {
return new MailProvider(accountManager);
}
}
然后可以为MailComponent
定义MailModule
。 LoginComponent
和MenuComponent
可能取决于MailComponent
。
@ApplicationScoped
@Component(modules = MailModule.class)
public interface MailComponent {
MailProvider mailProvider();
AccountManager accountManager();
}
@ActivityScoped
@Component(dependencies = MailComponent.class)
public interface LoginComponent {
LoginPresenter presenter();
}
@ActivityScoped
@Component(dependencies = MailComponent.class)
public interface MenuComponent {
MenuPresenter presenter();
}
MailComponent
可以初始化,如下所示,可以在MenuComponent
和LoginComponent
中再次使用。
MailComponent mailComponent = DaggerMailComponent.builder().build();
DaggerMenuComponent.builder().mailComponent(mailComponent).build();
DaggerLoginComponent.builder().mailComponent(mailComponent).build()