前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Dagger Android支持库(译文)

Dagger Android支持库(译文)

作者头像
haifeiWu
发布2018-09-11 10:13:20
9720
发布2018-09-11 10:13:20
举报
文章被收录于专栏:haifeiWu与他朋友们的专栏

与其他依赖注入框架相比,Dagger 2 最大的优点是他不使用反射,严格的生成实现类,这意味着他可以使用在 Android 应用上。但是在Android上使用仍有一些注意事项。

使用Dagger编写Android应用程序的一个主要困难是,许多Android框架类都由操作系统本身实例化,如Activity和Fragment,但如果Dagger可以创建所有注入的对象,则效果最佳。

相反,您必须在生命周期方法中执行成员注入。 这意味着许多类最终看起来像:

代码语言:javascript
复制
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
  }
}

这有一些问题:

  1. 复制粘贴代码使得以后很难重构。 随着越来越多的开发人员复制粘贴该块,更少的人会知道它实际上做了什么。
  2. 更重要的是,它需要请求注入类型(FrombulationActivity)来了解其注入器。 即使这是通过接口而不是具体类型完成的,它也打破了依赖注入的核心原则:类不应该知道它是如何注入的。

dagger.android中的类提供了一种简化此模式的方法。

注入 Activity 对象

  1. 在应用程序组件中安装 AndroidInjectionModule,以确保这些基本类型所需的所有绑定都可用。
  2. 首先编写实现AndroidInjector 的@Subcomponent,并使用扩展AndroidInjector.Builder 的@ Subcomponent.Builder: @Subcomponent(modules = ...) public interface YourActivitySubcomponent extends AndroidInjector<YourActivity> { @Subcomponent.Builder public abstract class Builder extends AndroidInjector.Builder<YourActivity> {} }
  3. 定义子组件后,通过定义绑定子组件构建器的模块并将其添加到注入应用程序的组件,将其添加到组件层次结构中: @Module(subcomponents = YourActivitySubcomponent.class) abstract class YourActivityModule { @Binds @IntoMap @ActivityKey(YourActivity.class) abstract AndroidInjector.Factory<? extends Activity> bindYourActivityInjectorFactory(YourActivitySubcomponent.Builder builder); } @Component(modules = {..., YourActivityModule.class}) interface YourApplicationComponent {}

专业提示:如果你的 subcomponent 和他的 builder 没有其他方法或者超类型,而不是步骤2中提到的方法或超类型,则可以使用 @ContributesAndroidInjector 为您生成它们。 而不需要第2步和第3步,添加一个返回活动的抽象模块方法,使用@ContributesAndroidInjector对其进行注释,并指定要安装到子组件中的模块。 如果子组件需要范围,则还要将范围注释应用于该方法。

代码语言:javascript
复制
@ActivityScope
@ContributesAndroidInjector(modules = { /* modules to install into the subcomponent */ })
abstract YourActivity contributeYourActivityInjector();
  1. 接下来,让 Application 实现 HasActivityInjector 接口和 注入@Inject a DispatchingAndroidInjector ,实现 activityInjector() 方法: public class YourApplication extends Application implements HasActivityInjector { @Inject DispatchingAndroidInjector<Activity> dispatchingActivityInjector; @Override public void onCreate() { super.onCreate(); DaggerYourApplicationComponent.create() .inject(this); } @Override public AndroidInjector<Activity> activityInjector() { return dispatchingActivityInjector; } }
  2. 最后,在 Activity.onCreate() 方法,super.onCreate() 之前实现 AndroidInjection.inject(this) public class YourActivity extends Activity { public void onCreate(Bundle savedInstanceState) { AndroidInjection.inject(this); super.onCreate(savedInstanceState); } }

他是如何工作的(原理)

AndroidInjection.inject() 从 Application 获取 DispatchingAndroidInjector 并将 activity 传递给 inject(Activity)。DispatchingAndroidInjector 为您的活动类(即YourActivitySubcomponent.Builder)查找AndroidInjector.Factory,创建AndroidInjector(即YourActivitySubcomponent),并将您的活动传递给 inject(YourActivity)。

注入 Fragment 对象

注入 Fragment 就像注入 Activity 一样。以相同的方式定义 subcomponent,将 Activity 类型参数替换为 Fragment,将 @ActivityKey 替换为 @FragmentKey,将 HasActivityInjector 替换为 HasFragmentInjector。

像在 Activity 中 onCreate() 注入一样,Fragment 在 onAttach() 注入。

与为 Activitys 定义的模块不同,您可以选择在何处安装 Fragments 模块。 您可以将Fragment组件作为另一个Fragment组件,Activity组件或Application组件的子组件 - 这一切都取决于Fragment所需的其他绑定。 在确定组件位置后,使相应的类型实现 HasFragmentInjector。 例如,如果您的 Fragment 需要来自 YourActivitySubcomponent 的绑定,那么您的代码将如下所示:

代码语言:javascript
复制
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 的组件。

也同时包括如下类型:

  • DaggerService 和 DaggerIntentService
  • DaggerBroadcastReceiver
  • DaggerContentProvider

注意:只有在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)。

集成方式如下:

代码语言:javascript
复制
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

版权声明:非特殊声明均为本站原创作品,转载时请注明作者和原文链接。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 注入 Activity 对象
  • 他是如何工作的(原理)
  • 注入 Fragment 对象
  • 基本类型支持
  • 支持库
  • 注入时机
  • 问题
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档