匕首2中的示波器

2022-09-01 16:47:33

我可能错过了一些东西,但我认为像@Singleton这样的作用域用于定义“作用域生命周期”。

我在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 采用 :MenuPresenterLoginPresenter@InjectMailProviderAccountManager

  @Inject public MenuPresenter(MailProvider mailProvider) { ... }

  @Inject public LoginPresenter(AccountManager accountManager) { ... }

但是每次我使用这些组件创建一个或我得到一个全新的和实例时。我认为它们在同一范围内,因此应该是单例(在同一范围内)。MenuPresenterLoginPresenterMailProviderAccountManager

我是否完全理解了什么错误。如何在匕首 2 中为多个组件定义真正的单例?


答案 1

我假设和是单独使用的,例如在 和 .每个组件都内置于 中。如果是这样,每次创建新活动时都会重新创建组件,模块和依赖项也是如此,而与它们绑定到的范围无关。因此,您每次都会获得 和 的新实例。LoginComponentMenuComponentLoginActivityMenuActivityActivity.onCreateMainProviderAccountManager

MenuActivity并且具有单独的活动周期,因此从的依赖项不能同时在它们中都是单例的。您需要的是声明具有作用域的根组件(例如,在应用程序子类中),使其并依赖于它。活动级别组件不能@Singleton作用域,最好使用注释创建自己的作用域,例如:LoginActivityMailModule@SingletonMenuComponentLoginComponent@Scope

@Retention(RetentionPolicy.RUNTIME)
@Scope
public @interface MenuScope {
}

或者,您可以将它们保留为无范围。

关于范围,这里有一个来自最初的Dagger 2提案的简介:

@Singleton
@Component(modules = {…})
public interface ApplicationComponent {}

该声明使匕首能够强制执行以下约束:

  • 给定组件可能只有未作用域或声明范围的绑定(包括类上的作用域批注)。即,一个组件不能表示两个作用域。如果未列出任何作用域,则只能取消绑定的作用域。
  • 一个作用域组件只能有一个作用域内的依赖项。这是强制两个组件不各自声明自己的作用域绑定的机制。例如,两个单例组件,每个组件都有自己的@Singleton缓存将被破坏。
  • 组件的作用域不得出现在其任何传递依赖项中。例如:SessionScoped -> RequestScoped -> SessionScoped没有任何意义,是一个错误。
  • @Singleton的特殊处理方式是因为它不能有任何作用域内的依赖项。每个人都希望辛格尔顿是“根”。

这种规则组合的目标是强制在应用范围时,组件由我们以前在 Dagger 1.0 plus()'d ObjectGraphs 中具有的相同结构组成,但能够对所有绑定及其作用域具有静态知识。换句话说,当应用作用域时,这会将图形限制为只能正确构造的图形。

从我自己的实践来看,更清楚的是根本不使用。取而代之的是,我使用.它用于在整个应用程序上定义单例,并且没有其他限制。@Singleton@ApplicationScope@Singleton

希望这有助于您:)。快速理解是相当棘手的,需要时间,至少对我来说是这样。


答案 2

您可以执行以下操作来为多个组件定义真正的单一实例。我假设并成为不同的范围。@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);
  }
}

然后可以为 .和 可以依赖于 .MailComponentMailModuleLoginComponentMenuComponentMailComponent

@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();
}

可以按如下所示进行初始化,并且可以在下面再次使用。MailComponentMenuComponentLoginComponent

MailComponent mailComponent = DaggerMailComponent.builder().build();

DaggerMenuComponent.builder().mailComponent(mailComponent).build();

DaggerLoginComponent.builder().mailComponent(mailComponent).build()            

推荐