匕首 2,范围 + 注释



我从来没有使用过像dagger这样令人困惑的DI框架! - 但是,我试图绕开它。

我有两个范围:ActivityScope 和 FragmentScope

在提供的一些样本中 StatisticsFragment 中.java您可以看到例如用范围注释的片段

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

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

问题 2:在生成的代码中的哪个位置可以看到使用了哪个范围?我的片段注入了一个演示者和一个身份验证提供程序。AuthProvider 使用 Singleton(在 AppModule 中)进行注释,表示器在 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);
}

登录模块.java


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

登录弗拉格特.java


public class LoginFragment extends DaggerFragment {
@Inject
LoginContract.Presenter presenter;
@Inject
Provider<MyAuthClass> myAuthClass;
... 
}

每次创建片段时都会创建演示器,myAuthClass 只创建一次并且是单例。 完美 - 但我不知道这是如何工作的!!

DaggerFragment#onAttach 必须以某种方式知道 Presenter 是一个"本地"单例,而 MyAuthClass 是一个全局单例......

Scope 是告诉 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()时,你的对象1是无作用域的,所以Dagger会做它的默认设置:创建一个全新的。但是,当您调用fooComponent.getYourObject2()时,如果您已将 YourObject2 配置为@FooScoped,Dagger 将在该 FooComponent 的整个生命周期内只返回一个实例。当然,您可以创建两个 FooComponent 实例,但您永远不会看到来自同一@FooScoped组件 (FooComponent) 的@FooScoped对象的多个实例。

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


现在回答您的问题:

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

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

但是,向片段添加@Inject注释可能是一个有争议的举动,因为Android基础设施能够自己创建和销毁片段实例。Android 重新创建的对象不会是作用域的对象,并且由于DaggerFragment 的超类行为,它将在 Attach 上重新注入其成员。我认为更好的做法是从构造函数中删除@Inject注释,并坚持对 Fragment 进行字段注入。此时你可以删除范围,因为 Dagger 永远不会创建你的片段,所以它永远不会决定是创建一个新的还是返回一个现有的。

问题 2:在生成的代码中的哪个位置可以看到使用了哪个范围?我的片段注入了一个演示者和一个身份验证提供程序。AuthProvider 使用 Singleton(在 AppModule 中)进行注释,表示器在 UIModule 中定义 -> LoginModule

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

最新更新