与其他依赖注入框架相比,Dagger 2 最大的优点是他不使用反射,严格的生成实现类,这意味着他可以使用在 Android 应用上。但是在Android上使用仍有一些注意事项。
使用Dagger编写Android应用程序的一个主要困难是,许多Android框架类都由操作系统本身实例化,如Activity和Fragment,但如果Dagger可以创建所有注入的对象,则效果最佳。
相反,您必须在生命周期方法中执行成员注入。 这意味着许多类最终看起来像:
public class FrombulationActivity extends Activity {
@Inject Frombulator frombulator;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// DO THIS FIRST. Otherwise frombulator might be null!
((SomeApplicationBaseType) getContext().getApplicationContext())
.getApplicationComponent()
.newActivityComponentBuilder()
.activity(this)
.build()
.inject(this);
// ... now you can write the exciting code
}
}
这有一些问题:
dagger.android中的类提供了一种简化此模式的方法。
专业提示:如果你的 subcomponent 和他的 builder 没有其他方法或者超类型,而不是步骤2中提到的方法或超类型,则可以使用 @ContributesAndroidInjector 为您生成它们。 而不需要第2步和第3步,添加一个返回活动的抽象模块方法,使用@ContributesAndroidInjector对其进行注释,并指定要安装到子组件中的模块。 如果子组件需要范围,则还要将范围注释应用于该方法。
@ActivityScope
@ContributesAndroidInjector(modules = { /* modules to install into the subcomponent */ })
abstract YourActivity contributeYourActivityInjector();
AndroidInjection.inject() 从 Application 获取 DispatchingAndroidInjector 并将 activity 传递给 inject(Activity)。DispatchingAndroidInjector 为您的活动类(即YourActivitySubcomponent.Builder)查找AndroidInjector.Factory,创建AndroidInjector(即YourActivitySubcomponent),并将您的活动传递给 inject(YourActivity)。
注入 Fragment 就像注入 Activity 一样。以相同的方式定义 subcomponent,将 Activity 类型参数替换为 Fragment,将 @ActivityKey 替换为 @FragmentKey,将 HasActivityInjector 替换为 HasFragmentInjector。
像在 Activity 中 onCreate() 注入一样,Fragment 在 onAttach() 注入。
与为 Activitys 定义的模块不同,您可以选择在何处安装 Fragments 模块。 您可以将Fragment组件作为另一个Fragment组件,Activity组件或Application组件的子组件 - 这一切都取决于Fragment所需的其他绑定。 在确定组件位置后,使相应的类型实现 HasFragmentInjector。 例如,如果您的 Fragment 需要来自 YourActivitySubcomponent 的绑定,那么您的代码将如下所示:
public class YourActivity extends Activity
implements HasFragmentInjector {
@Inject DispatchingAndroidInjector<Fragment> fragmentInjector;
@Override
public void onCreate(Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
// ...
}
@Override
public AndroidInjector<Fragment> fragmentInjector() {
return fragmentInjector;
}
}
public class YourFragment extends Fragment {
@Inject SomeDependency someDep;
@Override
public void onAttach(Activity activity) {
AndroidInjection.inject(this);
super.onAttach(activity);
// ...
}
}
@Subcomponent(modules = ...)
public interface YourFragmentSubcomponent extends AndroidInjector<YourFragment> {
@Subcomponent.Builder
public abstract class Builder extends AndroidInjector.Builder<YourFragment> {}
}
@Module(subcomponents = YourFragmentSubcomponent.class)
abstract class YourFragmentModule {
@Binds
@IntoMap
@FragmentKey(YourFragment.class)
abstract AndroidInjector.Factory<? extends Fragment>
bindYourFragmentInjectorFactory(YourFragmentSubcomponent.Builder builder);
}
@Subcomponent(modules = { YourFragmentModule.class, ... })
public interface YourActivityOrYourApplicationComponent { ... }
因为 DispatchingAndroidInjector 在运行时通过类查找适当的 AndroidInjector.Factory,所以基类可以实现HasActivityInjector / HasFragmentInjector / etc以及调用AndroidInjection.inject()。 所有每个子类需要做的是绑定相应的 @Subcomponent。 如果您没有复杂的类层次结构,Dagger提供了一些基本类型,例如DaggerActivity和 DaggerFragment。 Dagger 还为同一目的提供了 DaggerApplication - 您需要做的就是扩展它并覆盖applicationInjector()方法以返回应该注入 Application 的组件。
也同时包括如下类型:
注意:只有在AndroidManifest.xml中注册BroadcastReceiver时才应使用DaggerBroadcastReceiver。 在您自己的代码中创建BroadcastReceiver时,使用构造函数注入。
对于Android支持库的用户,dagger.android.support 包中存在相同类型。请注意,虽然支持Fragment用户必须绑定AndroidInjector.Factory <? extends android.support.v4.app.Fragment>,对于AppCompat,用户应该继续实现AndroidInjector.Factory <? extends Activity> 而不是 <? extends AppCompatActivity>(或FragmentActivity)。
集成方式如下:
dependencies {
compile 'com.google.dagger:dagger-android:2.x'
compile 'com.google.dagger:dagger-android-support:2.x' // if you use the support libraries
annotationProcessor 'com.google.dagger:dagger-android-processor:2.x'
}
尽可能优先使用构造函数注入,因为 javac 将确保在设置之前不引用任何字段,这有助于避免NullPointerExceptions。 当需要注射成员时(如上所述),优选尽早注射。 出于这个原因,DaggerActivity 在调用 super.onCreate() 之前立即在 onCreate() 中调用 AndroidInjection.inject(),而 DaggerFragment 在 onAttach() 中执行相同操作,这也可以防止重新附加Fragment时出现不一致。
在Activity中的super.onCreate() 之前调用AndroidInjection.inject() 是至关重要的,因为对 super 的调用会在配置更改期间附加前一个活动实例中的 Fragments,从而注入 Fragments。 为了使Fragment注入成功,必须已经注入了Activity。 对于 ErrorProne 的用户,在 super.onCreate() 之后调用 AndroidInjection.inject() 是一个编译器错误。
AndroidInjector.Factory 范围:
AndroidInjector.Factory 旨在成为无状态接口,因此实现者不必担心管理与将要注入的对象相关的状态。当DispatchingAndroidInjector 请求 AndroidInjector.Factory 时,它通过 Provider 执行此操作,以便它不会显式保留工厂的任何实例。 因为Dagger生成的 AndroidInjector.Builder 实现确实保留了正在注入的 Activity / Fragment / etc的实例,所以将范围应用于提供它们的方法是一个编译时错误。 如果您肯定您的 AndroidInjector.Factory 没有为注入的对象保留实例,则可以通过将 @SuppressWarnings(“dagger.android.ScopedInjectoryFactory”) 应用于模块方法来抑制此错误。
作 者:ChanghuiN
原文链接:https://cloud.tencent.com/developer/article/1333292
版权声明:非特殊声明均为本站原创作品,转载时请注明作者和原文链接。