如何在Dagger 2中使用@Scope

时间:2015-12-23 22:30:38

标签: java android dagger-2

我在@Scope注释上阅读了很多材料,但仍然没有完全理解我所知道的是否正确。

有人可以解释@Scope的确切内容吗?在哪里使用?它是如何使用的?

仅在定义组件时使用吗?

也是这样定义的范围?:

@Scope
public @interface SomeScope {
}

像这样使用?:

@SomeScope
@Component(modules = {
        HeaterModule.class,
        PumpModule.class
})
public interface MainActivityComponent {
    void inject(MainActivity mainActivity);
    CoffeeMaker maker();
}

2 个答案:

答案 0 :(得分:2)

Java EE应用程序范围的定义说明如下:

  

对于使用注入另一个bean类的bean的Web应用程序,   bean需要能够在持续时间内保持状态   用户与应用程序的交互。定义此状态的方法   是给豆子一个范围。

让它与Android联系起来。范围对范围提供者提供的依赖关系生命周期施加了某些限制。

例如,假设我们希望从@Singleton d组件获得@ActivityScope依赖关系。只要活动,该组件就会存在。一旦活动被销毁并再次创建,我们的组件就会相应地实例化,并且我们的“@ Singleton'依赖性也会再次创建。

总结一下,我们的@Singleton依赖项与它们关联的@Components一样长 - 这是我认为最实用的解释。

在内部,一旦Dagger在具有指定范围的@Component提供方法中通知,它就会为依赖项提供创建ScopedProvider。否则,将创建Factory

ScopedProvider的get方法是一种双重检查单例方法:

public T get() {
    // double-check idiom from EJ2: Item 71
    Object result = instance;
    if (result == UNINITIALIZED) {
      synchronized (this) {
        result = instance;
        if (result == UNINITIALIZED) {
          instance = result = factory.get();
        }
      }
    }
    return (T) result;
  }

要查看实用的@Scope用法,您可以查看我的一个示例:

https://github.com/dawidgdanski/AccountAuthenticatorExample

希望,这在某种程度上是有帮助的。

编辑1 : @Fshamri提供的文章解释得更好。

编辑2

让我们考虑以下结构:

组件:

@ActivityScope //Dagger ignores the annotation put atop the @Component. I put it there just for readability
@Component(dependencies = DependencyGraph.class,
        modules = {ActivityModule.class})
public interface ActivityComponent {
    void inject(MainActivity mainActivity);
    void inject(SignUpActivity signUpActivity);
    void inject(SignInActivity signInActivity);

提供依赖项的模块:

    @Module
    public class ActivityModule {

    private final Activity activity;

    public ActivityModule(Activity activity) {
        this.activity = activity;
    }

    @Provides
    @ActivityScope
    MainView provideMainView() {
        return (MainView) activity;
    }

    @Provides
    SignInView provideSignInView() {
        return (SignInView) activity;
    }
    }

@ActivityScope扩展了@Scope注释 - Dagger解释它与@Singleton的解释方式相同。 ActivityModule提供了2次观看:@ActivityScope d MainViewSignInView没有任何范围。在编译期间,Dagger的注释处理器为两个视图创建Provider s。 MainView&和SignInView生成的Provider之间的区别在于MainView Dagger生成ScopedProvider(因为我们明确地请求这种提供者@ActivityScope)而对于SignInView Dagger会定期生成Factory个提供商。

ScopedProvider的合同如上所示。但是,Factory提供商的合同看起来如下:

@Generated("dagger.internal.codegen.ComponentProcessor")
public final class ActivityModule_ProvideSignInViewFactory implements Factory<SignInView> {
  private final ActivityModule module;

  public ActivityModule_ProvideSignInViewFactory(ActivityModule module) {  
    assert module != null;
    this.module = module;
  }
  @Override
  public SignInView get() {  
    SignInView provided = module.provideSignInView();
    if (provided == null) {
      throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
    }
    return provided;
  }

  public static Factory<SignInView> create(ActivityModule module) {  
    return new ActivityModule_ProvideSignInViewFactory(module);
  }
}

结论: 1. ScopedProvider是一种经典的复核单身模式。它保证只创建一个依赖项实例。 2. Factory的{​​{1}}方法只是从模块中分配依赖项,这意味着它可以在每次请求时分发新的依赖项实例(事实上,在示例中,Activity只转换为SignInView,它仍然给我们一个实例,但这是我的例子中的复制粘贴逻辑)。 3. Dagger关注@Scopes以及@Modules中的提供方法,而不是@Components。

我鼓励您下载示例并构建项目,然后查看生成的get()组件和模块的合同。

希望现在更容易理解。

答案 1 :(得分:1)

你看过this article了吗?

  

在Dagger 2中,范围机制关注保持单个实例   类,只要其范围存在。在实践中,它意味着实例   @ApplicationScope中的作用域与Application对象一样长。   只要活动存在,@ ActivityScope就会保留引用(for   例如,我们可以在所有类之间共享任何类的单个实例   此活动中托管的片段)。在短期内,我们“本地化   单身人士“只要与范围本身一样长寿。