Dagger2 系列(四)Dagger2.Android基本原理

前言

上篇文章我們介紹了dagger2.android的如何使用,知其然知其所以然疯趟,本篇我們一起來(lái)看下艺智,dagger2.android是怎么在dagger2基礎(chǔ)上實(shí)現(xiàn)注入的。

注意

  • 本篇不講代碼生成過(guò)程汰翠,后續(xù)文章介紹。
  • 本篇講解dagger2.android注入原理肯定還是dagger2注入原理昭雌,所以請(qǐng)先閱讀前3篇文章复唤,了解Provider、Builder 烛卧、SubcomponentImpl佛纫、MembersInjector等主要類作用。

dagger2和dagger2.android 調(diào)用注入的區(qū)別

調(diào)用區(qū)別我們上篇文章已經(jīng)詳細(xì)講到总放,本篇從調(diào)用區(qū)別引入原理實(shí)現(xiàn)呈宇。dagger2中acitivity實(shí)現(xiàn)注入代碼如下:

private void initInjector() {
      mComponent = getAppComponent()
          .mainActivityComponent()
          .activity(this)
          .build();
}

dagger2.anodriod中acitivity實(shí)現(xiàn)注入代碼如下:
Application的改造代碼:

public class MyApplication extends Application implements HasActivityInjector {

    @Inject
    DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;

    @Override
    public void onCreate() {
        super.onCreate();
        DaggerMyAppComponent.create().inject(this);
    }
    @Override
    public AndroidInjector<Activity> activityInjector() {
        return dispatchingAndroidInjector;
    }
}

activity的注入代碼

@Override
protected void onCreate(@Nullable Bundle  savedInstanceState) {
        AndroidInjection.inject(this);
        super.onCreate(savedInstanceState);
}

區(qū)別為:
dagger2.android的調(diào)要先改造了Application,activity里不需要再調(diào)用具體的component接口方法局雄。
代碼雖有區(qū)別,完成任務(wù)是一樣的甥啄。完成:
拿到MainActivityComponent的的實(shí)現(xiàn)類,然后實(shí)現(xiàn)MainActivity的注入炬搭。
我們本篇就是要講解dagger2.android是怎么完成這個(gè)過(guò)程的蜈漓,從代碼上看就是,DaggerMyAppComponent.create().inject(this)和 AndroidInjection.inject(this)做了什么宫盔。還是以MainActivity注入為例融虽。

dagger2.android 注入原理

DaggerMyAppComponent.create().inject(this)

先給出這行代碼作用的結(jié)論:

將MainActivityComponent等subComponent的實(shí)現(xiàn)類的工廠實(shí)例緩存(簡(jiǎn)單理解方式,實(shí)際緩存是工廠實(shí)例進(jìn)一步封裝)起來(lái)灼芭,activity注入時(shí)候備用衣形。

兩個(gè)問(wèn)題:

  • 緩存在哪?
    緩存在Application的dispatchingAndroidInjector中姿鸿。
  • 如何緩存?
    也是通過(guò)注入方式緩存倒源。
    帶著結(jié)論我們開始擼代碼苛预,DaggerMyAppComponent.create()方法:
 public static MyAppComponent create() {
    return new Builder().build();
  }
public static final class Builder {
    private Builder() {}

    public MyAppComponent build() {
      return new DaggerMyAppComponent(this);
    }
  }

就是返回了DaggerMyAppComponent實(shí)例。DaggerMyAppComponent初始化又做了什么:

 private DaggerMyAppComponent(Builder builder) {
    initialize(builder);
  }
 private void initialize(final Builder builder) {
    this.mainActivitySubcomponentBuilderProvider =
        new Provider<
            AllActivitysModule_ContributeMainActivitytInjector.MainActivitySubcomponent.Builder>() {
          @Override
          public AllActivitysModule_ContributeMainActivitytInjector.MainActivitySubcomponent.Builder
           //待會(huì)要回調(diào)此處笋熬,請(qǐng)注意  
            get() {
            return new MainActivitySubcomponentBuilder();
          }
        };
    this.secondActivitySubcomponentBuilderProvider =
......
  }

實(shí)例化了mainActivitySubcomponentBuilderProvider 热某、secondActivitySubcomponentBuilderProvider 等SubcomponentBuilderProvider ,這里Provider細(xì)節(jié)不再深入,簡(jiǎn)單理解為Subcomponent實(shí)現(xiàn)類的工廠類昔馋。這里完成了Subcomponent實(shí)現(xiàn)類的工廠類的實(shí)例化筹吐,接下來(lái)就是把他緩存起來(lái)了。
inject()方法源碼:

@Override
public void inject(MyApplication application) {
    injectMyApplication(application);
}

private MyApplication injectMyApplication(MyApplication instance) {
    MyApplication_MembersInjector.injectDispatchingAndroidInjector(
        instance, getDispatchingAndroidInjectorOfActivity());
    return instance;
  }
}

代碼調(diào)用到了MyApplication_MembersInjector的injectDispatchingAndroidInjector方法秘遏,第二個(gè)參數(shù)getDispatchingAndroidInjectorOfActivity()方法返回的是對(duì)上面我初始化的Provider進(jìn)一步封裝后的結(jié)果丘薛。在dagger2中MembersInjector是真正完成注入的地方,我們看進(jìn)去為MyApplication注入了什么邦危。

public static void injectDispatchingAndroidInjector(
      MyApplication instance, DispatchingAndroidInjector<Activity> dispatchingAndroidInjector) {
    instance.dispatchingAndroidInjector = dispatchingAndroidInjector;
}

到這里洋侨,真正的我們之前說(shuō)的:用注入的方式把subComponent的實(shí)現(xiàn)類的工廠實(shí)例緩存在Application的dispatchingAndroidInjector中。

AndroidInjection.inject(this)

這行代碼完成的工作是:

從Application的dispatchingAndroidInjector中獲取MainActivityComponent的的實(shí)現(xiàn)類實(shí)例倦蚪,然后完成MainActivity的注入希坚。

public static void inject(Activity activity) {
    checkNotNull(activity, "activity");
    Application application = activity.getApplication();
    if (!(application instanceof HasActivityInjector)) {
      throw new RuntimeException(
          String.format(
              "%s does not implement %s",
              application.getClass().getCanonicalName(),
                   HasActivityInjector.class.getCanonicalName()));
    }

AndroidInjector<Activity> activityInjector =
        ((HasActivityInjector) application).activityInjector();
    checkNotNull(activityInjector, "%s.activityInjector() returned null", application.getClass());

 activityInjector.inject(activity);
  }

代碼解釋:異常處理,然后得到application的dispatchingAndroidInjector陵且,調(diào)用其inject(activity)方法裁僧。
繼續(xù)看到DispatchingAndroidInjector中inject方法:

  @Override
  public void inject(T instance) {
    boolean wasInjected = maybeInject(instance);
    if (!wasInjected) {
      throw new IllegalArgumentException(errorMessageSuggestions(instance));
    }
  }
public boolean maybeInject(T instance) {
    Provider<AndroidInjector.Factory<? extends T>> factoryProvider =
        injectorFactories.get(instance.getClass());
    if (factoryProvider == null) {
      return false;
    }

    @SuppressWarnings("unchecked")
    AndroidInjector.Factory<T> factory = (AndroidInjector.Factory<T>) factoryProvider.get();
    try {
      AndroidInjector<T> injector =
          checkNotNull(
              factory.create(instance), "%s.create(I) should not return null.", factory.getClass());

      injector.inject(instance);
      return true;
    } catch (ClassCastException e) {
      throw new InvalidInjectorBindingException(
          String.format(
              "%s does not implement AndroidInjector.Factory<%s>",
              factory.getClass().getCanonicalName(), instance.getClass().getCanonicalName()),
          e);
    }
  }

代碼又調(diào)用到maybeInject方法,還是以MainActivity為例慕购,

  • 獲得MainActivity對(duì)應(yīng)我們之前緩存的Provider
  • 調(diào)用get方法獲得MainActivitySubcomponentBuilder實(shí)例factory(參考上面provider實(shí)例化的地方get的具體實(shí)現(xiàn))
  • 調(diào)用MainActivitySubcomponentBuilder的create方法聊疲,create方法中又調(diào)用到build方法:
@Override
public AllActivitysModule_ContributeMainActivitytInjector.MainActivitySubcomponent build() {
      if (seedInstance == null) {
        throw new IllegalStateException(MainActivity.class.getCanonicalName() + " must be set");
      }
      return new MainActivitySubcomponentImpl(this);
    }
}

最終我終于得到了MainActivitySubcomponent的實(shí)現(xiàn)類MainActivitySubcomponentImpl,回到上面主流程中脓钾,調(diào)用了其inject方法:

@Override
public void inject(MainActivity arg0) {
     injectMainActivity(arg0);
}

private MainActivity injectMainActivity(MainActivity instance) {
      MainActivity_MembersInjector.injectClassName(
          instance, MainActivityModule_ProvideNameFactory.proxyProvideName());
      MainActivity_MembersInjector.injectSp(instance, getSharedPreferences());
      MainActivity_MembersInjector.injectPresenter(instance, getMainPresenter());
      MainActivity_MembersInjector.injectS1(instance, provideStudentProvider.get());
      MainActivity_MembersInjector.injectS2(instance, provideStudentProvider.get());
      return instance;
    }
}

到這里終于調(diào)用了各種MembersInjector完成了MainActivity的注入售睹。
最后一句話總結(jié)dagger2.android的注入原理:

將MainActivityComponent的實(shí)現(xiàn)類的工廠實(shí)例(簡(jiǎn)單理解)緩存起來(lái),MainActivity注入時(shí)取出工廠實(shí)例可训,build構(gòu)建得到MainActivitySubcomponentImpl后昌妹,完成MainActivity注入。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末握截,一起剝皮案震驚了整個(gè)濱河市飞崖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌谨胞,老刑警劉巖固歪,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異胯努,居然都是意外死亡牢裳,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門叶沛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蒲讯,“玉大人,你說(shuō)我怎么就攤上這事灰署∨邪铮” “怎么了局嘁?”我有些...
    開封第一講書人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)晦墙。 經(jīng)常有香客問(wèn)我悦昵,道長(zhǎng),這世上最難降的妖魔是什么晌畅? 我笑而不...
    開封第一講書人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任但指,我火速辦了婚禮,結(jié)果婚禮上踩麦,老公的妹妹穿的比我還像新娘枚赡。我一直安慰自己,他們只是感情好谓谦,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開白布贫橙。 她就那樣靜靜地躺著,像睡著了一般反粥。 火紅的嫁衣襯著肌膚如雪卢肃。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,246評(píng)論 1 308
  • 那天才顿,我揣著相機(jī)與錄音莫湘,去河邊找鬼。 笑死郑气,一個(gè)胖子當(dāng)著我的面吹牛幅垮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播尾组,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼忙芒,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了讳侨?” 一聲冷哼從身側(cè)響起呵萨,我...
    開封第一講書人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎跨跨,沒想到半個(gè)月后潮峦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡勇婴,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年忱嘹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片耕渴。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡德谅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出萨螺,到底是詐尸還是另有隱情窄做,我是刑警寧澤,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布慰技,位于F島的核電站椭盏,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏吻商。R本人自食惡果不足惜掏颊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望艾帐。 院中可真熱鬧乌叶,春花似錦、人聲如沸柒爸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)捎稚。三九已至乐横,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間今野,已是汗流浹背葡公。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留条霜,地道東北人催什。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像宰睡,于是被迫代替她去往敵國(guó)和親蒲凶。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359