我从未使用像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只创建一次并且是singleton。 完美 - 但我不知道 HOW 这是否有效!!!
DaggerFragment#onAttach必须知道Presenter是一个“本地”单身人士而MyAuthClass是global - singleton ......
答案 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可以确定图中缺少组件工厂方法或注入,并且可以避免为它添加任何代码生成 - 这可能是为什么你没有看到任何。