Dagger 2,范围+注释

时间:2018-03-12 13:08:23

标签: dagger-2 dagger

我从未使用像这样令人困惑的DI框架! - 但是,我试着绕过它。

我有两个范围:ActivityScope和FragmentScope

StatisticsFragment.java提供的部分样本中,您会看到例如用范围注释的片段

@ActivityScoped
public class StatisticsFragment extends DaggerFragment implements 
StatisticsContract.View {
...
}

问题1: 这只是文档还是没有?在我的应用程序中,如果我注释具体片段是没有区别的。

问题2:在生成的代码中,我可以看到使用哪个范围?我的片段注入了一个Presenter和一个AuthProvider。 AuthProvider使用Singleton注释(在AppModule中),Presenter在UIModule中定义 - >的LoginModule

看起来像这样:

UIModule.java:

@Module(includes = AndroidSupportInjectionModule.class)
public abstract class UIModule {

    @ActivityScope
    @ContributesAndroidInjector(modules = LoginModule.class)
    abstract LoginActivity loginActivity();

    @ChildFragmentScope
    @ContributesAndroidInjector(modules = LoginModule.class)
    abstract LoginFragment loginFragment();

    @Binds
    //@ChildFragmentScope
    public abstract LoginContract.View loginView(final LoginFragment fragment);
}

LoginModule.java

@Module
public abstract class LoginModule {

    @Provides
    //@ChildFragmentScope
    static LoginContract.Presenter provideLoginPresenter(final LoginContract.View view, final BaseStore store) {
        return new LoginPresenter(view,store);
    }

}

LoginFragemt.java

public class LoginFragment extends DaggerFragment {
   @Inject
   LoginContract.Presenter presenter;

   @Inject
   Provider<MyAuthClass> myAuthClass;

   ... 
}
每次创建Fragment时都会创建

presenter,myAuthClass只创建一次并且是。 完美 - 但我不知道 HOW 这是否有效!!!

DaggerFragment#onAttach必须知道Presenter是一个“本地”单身人士而MyAuthClass是 - ......

1 个答案:

答案 0 :(得分:1)

范围是两种方式之一你可以告诉Dagger总是绑定同一个对象,而不是在每个注入请求上返回一个新创建的对象。 (另一种方式是手动方式:只需在@Provides方法中返回相同的对象。)

首先,范围概述:假设您有一个组件FooComponent,它具有@FooScope注释。您可以定义一个子组件BarComponent,它具有@BarScope注释。这意味着使用单个FooComponent实例,您可以根据需要创建任意数量的BarComponent实例。

@FooScoped
@Component(modules = /*...*/)
public interface FooComponent {
  BarComponent createBarComponent(/* ... */);  // Subcomponent factory method
  YourObject1 getYourObject1();  // no scope
  YourObject2 getYourObject2();  // FooScoped
}

@BarScoped
@Subcomponent(modules = /*...*/)
public interface BarComponent {
  YourObject3 getYourObject3();  // no scope
  YourObject4 getYourObject4();  // BarScoped
  YourObject5 getYourObject5();  // FooScoped
}

当您致电fooComponent.getYourObject1()时,YourObject1未展开,因此Dagger执行默认设置:创建一个全新的。但是,当您调用fooComponent.getYourObject2()时,如果您已将YourObject2配置为@FooScoped,则Dagger将在该FooComponent的整个生命周期内返回一个实例。当然,您可以创建两个FooComponent实例,但是您永远不会从同一个@FooScoped组件(FooComponent)中看到@FooScoped对象的多个实例。

现在进入BarComponent:getYourObject3()是无范围的,所以每次都返回一个新实例; getYourObject4()是@BarScoped,因此它为BarComponent的每个实例返回一个新实例;并且getYourObject5()是@FooScoped,因此您将在创建BarComponent的FooComponent实例中获得相同的实例。

现在回答您的问题:

  

问题1:这只是文档吗?在我的应用程序中,如果我注释具体片段是没有区别的。

在具有@Inject - 注释构造函数的类(如StatisticsFragment)中,添加范围注释不仅仅是文档:没有范围注释,任何注入StatisticsFragment的请求都将生成一个全新的注释。如果你只期望每个Activity有一个StatisticsFragment实例,这可能是令人惊讶的行为,但可能很难注意到差异。

但是,在片段中添加@Inject注释可能会引起争议,因为the Android infrastructure is able to create and destroy Fragment instances itself。 Android重新创建的对象作用域 的成员因DaggerFragment's superclass behavior而重新注入onAttach。我认为更好的做法是从构造函数中删除@Inject注释,并坚持使用Fragment的字段注入。此时你可以放弃范围,因为Dagger永远不会创建你的片段,因此它永远不会决定是创建新片段还是返回现有片段。

  

问题2:在生成的代码中,我可以看到使用哪个范围?我的片段注入了一个Presenter和一个AuthProvider。 AuthProvider使用Singleton注释(在AppModule中),Presenter在UIModule中定义 - &gt;的LoginModule

生成的代码和作用域总是在Component中生成;子组件将其实现生成为Component的内部类。对于每个作用域绑定,initialize方法中将有一个位置,其中Provider(例如AuthProvider)包装在DoubleCheck的实例中,该实例管理单例组件的双重检查锁定。如果没有人要求Dagger 创建一个对象(如StatisticsFragment),Dagger可以确定图中缺少组件工厂方法或注入,并且可以避免为它添加任何代码生成 - 这可能是为什么你没有看到任何。