Dagger 2 中的作用域
Scopes in Dagger 2
我可能漏掉了什么,但我认为像@Singleton 这样的作用域是用来定义 "scoped lifecycles".
我在 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
的全新实例。我认为它们在同一范围内,因此应该是单例(在同一范围内)。
我是不是理解错了。如何在 Dagger 2 中为多个组件定义一个真正的单例?
我假设 LoginComponent
和 MenuComponent
是分开使用的,例如在 LoginActivity
和 MenuActivity
中。每个组件都内置于 Activity.onCreate
。如果是这样,每次创建新 activity 时都会重新创建组件,模块和依赖项也会重新创建,而与它们绑定的范围无关。因此,您每次都会得到 MainProvider
和 AccountManager
的新实例。
MenuActivity
和 LoginActivity
有独立的生命周期,因此来自 MailModule
的依赖项不能在两者中都是单例。您需要的是声明具有 @Singleton
作用域的根组件(例如在 Application 子类中),使 MenuComponent
和 LoginComponent
依赖于它。 Activity 级别组件不能是@Singleton 范围,最好使用 @Scope
注释创建自己的范围,例如:
@Retention(RetentionPolicy.RUNTIME)
@Scope
public @interface MenuScope {
}
或者你可以让它们没有作用域。
这里是关于范围的简要介绍 Dagger 2 proposal:
@Singleton
@Component(modules = {…})
public interface ApplicationComponent {}
That declaration enables dagger to enforce the following constraints:
- A given component may only have bindings (including scope annotations on classes) that are unscoped or of the declared scope.
I.e. a component cannot represent two scopes. When no scope is
listed, bindings may only be unscoped.
- A scoped component may only have one scoped dependency. This is the mechanism that enforces that two components don’t each declare their
own scoped binding. E.g. Two Singleton components that each have
their own @Singleton Cache would be broken.
- The scope for a component must not appear in any of its transitive dependencies. E.g.: SessionScoped -> RequestScoped -> SessionScoped
doesn’t make any sense and is a bug.
- @Singleton is treated specially in that it cannot have any scoped dependencies. Everyone expects Singleton to be the “root”.
The goal of this combination of rules is to enforce that when scope is
applied, components are composed with the same structure that we used
to have with Dagger 1.0 plus()’d ObjectGraphs, but with the ability to
have static knowledge of all of the bindings and their scopes. To put
it another way, when scopes are applied, this limits the graphs than
can be built to only those that can be correctly constructed.
根据我自己的实践,完全不使用 @Singleton
更清楚。取而代之的是,我使用 @ApplicationScope
。它用于在整个应用程序上定义单例,并且没有像 @Singleton
那样的额外限制。
希望对您有所帮助:)。快速理解是非常棘手的,需要时间,至少对我来说是这样。
您可以执行以下操作来为多个组件定义一个真正的单例。我假设 @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);
}
}
那么可以为MailModule
定义一个MailComponent
。 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()
我可能漏掉了什么,但我认为像@Singleton 这样的作用域是用来定义 "scoped lifecycles".
我在 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
的全新实例。我认为它们在同一范围内,因此应该是单例(在同一范围内)。
我是不是理解错了。如何在 Dagger 2 中为多个组件定义一个真正的单例?
我假设 LoginComponent
和 MenuComponent
是分开使用的,例如在 LoginActivity
和 MenuActivity
中。每个组件都内置于 Activity.onCreate
。如果是这样,每次创建新 activity 时都会重新创建组件,模块和依赖项也会重新创建,而与它们绑定的范围无关。因此,您每次都会得到 MainProvider
和 AccountManager
的新实例。
MenuActivity
和 LoginActivity
有独立的生命周期,因此来自 MailModule
的依赖项不能在两者中都是单例。您需要的是声明具有 @Singleton
作用域的根组件(例如在 Application 子类中),使 MenuComponent
和 LoginComponent
依赖于它。 Activity 级别组件不能是@Singleton 范围,最好使用 @Scope
注释创建自己的范围,例如:
@Retention(RetentionPolicy.RUNTIME)
@Scope
public @interface MenuScope {
}
或者你可以让它们没有作用域。
这里是关于范围的简要介绍 Dagger 2 proposal:
@Singleton @Component(modules = {…}) public interface ApplicationComponent {}
That declaration enables dagger to enforce the following constraints:
- A given component may only have bindings (including scope annotations on classes) that are unscoped or of the declared scope. I.e. a component cannot represent two scopes. When no scope is listed, bindings may only be unscoped.
- A scoped component may only have one scoped dependency. This is the mechanism that enforces that two components don’t each declare their own scoped binding. E.g. Two Singleton components that each have their own @Singleton Cache would be broken.
- The scope for a component must not appear in any of its transitive dependencies. E.g.: SessionScoped -> RequestScoped -> SessionScoped doesn’t make any sense and is a bug.
- @Singleton is treated specially in that it cannot have any scoped dependencies. Everyone expects Singleton to be the “root”.
The goal of this combination of rules is to enforce that when scope is applied, components are composed with the same structure that we used to have with Dagger 1.0 plus()’d ObjectGraphs, but with the ability to have static knowledge of all of the bindings and their scopes. To put it another way, when scopes are applied, this limits the graphs than can be built to only those that can be correctly constructed.
根据我自己的实践,完全不使用 @Singleton
更清楚。取而代之的是,我使用 @ApplicationScope
。它用于在整个应用程序上定义单例,并且没有像 @Singleton
那样的额外限制。
希望对您有所帮助:)。快速理解是非常棘手的,需要时间,至少对我来说是这样。
您可以执行以下操作来为多个组件定义一个真正的单例。我假设 @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);
}
}
那么可以为MailModule
定义一个MailComponent
。 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()