dagger2 的安卓支持库的使用

将以下内容添加到build.gradle中(未包括dagger2基本依赖)

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'
}

为什么要使用dagger2的安卓支持库

很多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
  }
}

这样做有几个问题
1.复制粘贴代码会使重构变得困难,当越来越多的开发者复制粘贴那段代码,很少有人知道它实际做了什么。
2.更根本的是,它需要请求注入(FrombulationActivity)的类型来了解其注入器。即使这是通过接口而不是具体类型完成的,它打破了依赖注入的核心原则:类不应该知道注入的方式。
所以dagger2开发者弄出了这么一套框架。
怎么实现呢?
1.安装AndroidInjiectionModule在应用程序中以确保这些基本类型所需的所有绑定都可用。(就是引入依赖)
2.首先写一个SubComponent接口扩展AndroidInjector<YourActivity>,该接口有继承了AndroidInjector.Builder<YourActivity>的方法(注意注释)

@Subcomponent(modules = ...)
public interface YourActivitySubcomponent extends AndroidInjector<YourActivity> {
  @Subcomponent.Builder
  public abstract class Builder extends AndroidInjector.Builder<YourActivity> {}
}

3.在定义完Subcomponent后,添加它到你的component分层结构中,具体做法是定义一个绑定了subcomponent builder的module,再将该module添加到注入你Applicationa的component中。

@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 {}

Pro-tip:如果你的Subcomponent和它的builder没有其他方法或者supertypes,你可以使用ContributesAndroidInjector去自动生成上面两个步骤中的代码。添加一个抽象module并返回你的activity,并用@ContributesAndroidInjector,然后声明你想要安装到subcomponent中的modules,如果这个subcomponent需要scopes,在该方法中声明注释。

@ActivityScope
@ContributesAndroidInjector(modules = { /* modules to install into the subcomponent */ })
abstract YourActivity contributeYourActivityInjector();

4.让你的Application实现HasActivityInjector并且@Inject一个DispatchingAndroidInjector<Activity>并且从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;
  }
}

5.在你的Activity.onCreate()方法中在调用super.onCreate()方法前调用AndroidInjection.inject(this)方法

public class YourActivity extends Activity {
  public void onCreate(Bundle savedInstanceState) {
    AndroidInjection.inject(this);
    super.onCreate(savedInstanceState);
  }
}

6.完成

那么它是怎么工作的呢?

AndroidInjection.inject()得到了来自Application的DispatchingAndroidInjector<Activity>并将您的activity传递给inject(Activity)。DispatchingAndroidInjector查找AndroidInjector.Factory作为您的activity的类(这是YourActivitySubcomponent.Builder),创建了 AndroidInjector(这是YourActivitySubcomponent),并传递你的activity给inject(YourActivity)。

注入Fragment对象
注入一个Fragment和注入一个Activity一样简单。用同样的方法定义你的subcomponent,用Fragment.@FragmentKey和HasFragmentInjector
类型代替Activity.@ActivityKey和HasActivityInjector
用在onAttach()注入Fragments代替在onCreate()中的注入。
和在Activitys中定义modules不同,你有在何时为Fragments安装modules的选择。你可以让你的Fragment 成为另一个Fragment component,一个Activity component或者Application component的subcomponent。它取决于你的Fragment需要绑定哪个。在决定component位置后,让相应的类型(Activity)实现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 { ... }

基本框架类型
Dagger2提供了DaggerActivity DaggerFragment 和 DaggerApplication这些基本框架类型,实现了HasActivityInjector/HasFragment以及调用AndroidInjection.inject().
以下类型也包括在内:

注意: DaggerBroadcastReceiver只能在 BroadcastReceiver注册时使用AndroidManifest.xml。当 BroadcastReceiver在你自己的代码中创建时,更喜欢构造器注入。

支持库

对于Android支持库的用户,dagger.android.support包中存在并行类型 。请注意,尽管支持Fragment用户必须绑定AndroidInjector.Factory<? extends android.support.v4.app.Fragment>,但AppCompat用户应继续执行,AndroidInjector.Factory<? extends Activity>而不是<? extends AppCompatActivity>(或FragmentActivity)。

何时注射

只要有可能,构造方法注入是首选,因为它javac确保在设置之前没有引用字段,这有助于避免NullPointerExceptions。当需要成员注射(如上所述)时,倾向于尽早注射。为此,DaggerActivity 呼吁AndroidInjection.inject()立即onCreate(),调用之前 super.onCreate()DaggerFragment做同样的onAttach(),这也防止了矛盾,如果Fragment重新连接。

AndroidInjection.inject()在之前调用是非常重要super.onCreate()Activity,因为调用在配置更改期间从先前的活动实例中super附加Fragments,而这又会注入 Fragments。为了使Fragment注射成功,Activity 必须已经注射。对于ErrorProne的用户来说,调用AndroidInjection.inject()之后会出现编译器错误super.onCreate()

以上内容来自dagger2官网中的详解介绍。
更具体的参考了google的官方demo后,有了这么几个小结。
1.让Activity、Fragment和Application继承Dagger2提供的基本类型可以省去步骤4和5
2.由于Activity和Fragment在实现注入的时候,子组件及其构建器没有其他方法或supertypes,因此都可以使用Pro-tips中的方法自动生成代码。
3.在定制的Application中重写了applicationInjector()方法,该方法告诉Dagger如何制造我们的@Singleton Component。
4.为了进一步解耦,activity之间传值的时候,传值activity不用改,接收值的方法在接收activity的module中声明。Activity中接收值的变量需要用@Inject注释。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351

推荐阅读更多精彩内容