匕首的范围2

时间:2015-04-09 02:13:32

标签: java android dagger-2

我可能错过了一些东西,但我认为像@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();

}

MenuPresenterLoginPresenter都有一个@Inject构造函数。虽然MenuPresenter期望MailProvider作为参数,但LoginPresenter需要AccountManager

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

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

但每次我使用这些组件创建MenuPresenterLoginPresenter时,我都会获得MailProviderAccountManager的全新实例。我认为它们属于同一范围,因此应该是单一的(在同一范围内)。

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

2 个答案:

答案 0 :(得分:50)

我认为LoginComponentMenuComponent是分开使用的,例如在LoginActivityMenuActivity中。每个组件都内置在Activity.onCreate中。如果是这样,每次创建新活动时,都会重新创建组件,模块和依赖项,而与它们所绑定的范围无关。因此,您每次都会获得MainProviderAccountManager的新实例。

MenuActivityLoginActivity具有单独的活动周期,因此来自MailModule的依赖关系不能在这两者中都是单例。您需要的是声明具有@Singleton范围的根组件(例如在Application子类中),make MenuComponentLoginComponent依赖于它。活动级别组件不能是@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定义MailModuleLoginComponentMenuComponent可能取决于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可以初始化,如下所示,可以在MenuComponentLoginComponent中再次使用。

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

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

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