剖析Dagger2依賴注入

前言

本篇文章將結(jié)合我自己寫(xiě)的咖啡店賣咖啡的栗子的demo,結(jié)合代碼來(lái)分析一下Dagger2是如何來(lái)實(shí)現(xiàn)依賴注入的逾条。
在我的第一篇文章中有提到如何配置Dagger2以及Dagger2的幾個(gè)關(guān)鍵概念涝登,不清楚怎么配置的你有额,建議可以先看看我的第一篇文章癣猾,先配置好Dagger2再開(kāi)始學(xué)習(xí)下面的內(nèi)容晰骑,由于結(jié)合代碼适秩,大部分代碼都貼出來(lái)的,篇幅較長(zhǎng),做好心理準(zhǔn)備秽荞,前方預(yù)警骤公。

總是想著可以開(kāi)一家咖啡店,現(xiàn)在現(xiàn)實(shí)中開(kāi)不了扬跋,那就現(xiàn)在代碼里開(kāi)一家吧阶捆。程序員不僅能宅出一個(gè)世界,更重要的你能創(chuàng)建出一個(gè)你自己的世界钦听,是不是突然自己好厲害洒试! 好吧,不扯了彪见,回到現(xiàn)實(shí)中儡司,好好學(xué)習(xí)吧。
我先創(chuàng)建一家銷售咖啡的咖啡店余指,然后在里面買各種咖啡捕犬,黑咖啡呀等。既然是咖啡店酵镜,那肯定要有咖啡呀碉碉。所以咖啡就是我需要的一個(gè)對(duì)象。所以我的咖啡店還需要依賴于咖啡淮韭,沒(méi)咖啡垢粮,那怎么行,準(zhǔn)備好票子靠粪,來(lái)買我的咖啡吧蜡吧。根據(jù)這個(gè)需求,我的咖啡店類如下:

public class CoffeeShopActivity extends AppCompatActivity {
  // 1. 我要賣的咖啡對(duì)象占键,用inject注明要依賴的對(duì)象
  @Inject
  Coffee mCoffee ; 
  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      inject();
      operate();
  }
  //2.添加依賴關(guān)鍵代碼昔善。
  private void inject() {
        DaggerCoffeeShopComponent.builder().build().inject(this);
 
  }

  private void operate() {
      mCoffee.getCoffee();
  }
}

Coffee是一個(gè)很簡(jiǎn)單的類,里面提供了一個(gè)getCoffee方法畔乙,打印了一串信息而已君仆。

public class Coffee {
    private static final String TAG =     Coffee.class.getSimpleName();
    @Inject
    public Coffee(){

    }

    public void getCoffee() {
        Log.i(TAG, "black coffee");
    }
}

咖啡店里面是個(gè)很簡(jiǎn)單的依賴關(guān)系,CoffeeShopActivity依賴于類Coffee牲距,可以看到我們沒(méi)有用 new 來(lái)創(chuàng)建Coffee對(duì)象返咱,而是直接通過(guò)@Inject來(lái)標(biāo)明CoffeeShopActivity的mCoffee需要依賴注入,來(lái)實(shí)例化這個(gè)變量牍鞠。是不是很神奇,如果你知道了依賴注入是怎么注入的之后咖摹,你就不會(huì)覺(jué)得很神奇了。下面我們一層層地來(lái)剝開(kāi)這個(gè)“洋蔥”吧皮服。

首先在上面代碼里楞艾,成員變量mCoffee定義的時(shí)候参咙,添加了@Inject注釋,然后Coffee的構(gòu)造函數(shù)添加了@Inject注釋硫眯。這樣就CoffeeShopActivity告訴了Dagger2蕴侧,我需要Coffee的實(shí)例,然后Dagger2就去找到Coffee的構(gòu)造函數(shù)創(chuàng)建一個(gè)Coffee两入。難道就只要這兩個(gè)類就可以了嗎净宵,之前不是說(shuō)Component是目標(biāo)類與被注入類之間的橋梁?jiǎn)幔?Component呢? 沒(méi)錯(cuò)裹纳,我還沒(méi)貼出Componet呢择葡。自定義個(gè)Componet類如下:

@Component
public interface CoffeeShopComponent  {
   void inject(CoffeeShopActivity coffeeShopActivity);
}

這個(gè)Component是不是很簡(jiǎn)單,只有一個(gè)抽象函數(shù)剃氧,方法名是inject敏储,方法名不是必須是inject,也可以是其他名字朋鞍,但是參數(shù)一定要是你的目標(biāo)類已添,而且注意哦,不能是Activity滥酥,一定要是目標(biāo)類自己的類名更舞。在第一篇文章里面就有提到過(guò),這里再?gòu)?qiáng)調(diào)一下坎吻,Dagger框架是通過(guò)參數(shù)的類型以及返回值類型缆蝉,找到要依賴的類,從而建立聯(lián)系的瘦真,所以類名一定要是直接要注入依賴的目標(biāo)類刊头,返回值也是要注入的類

好了诸尽,注射器(Component)寫(xiě)好了芽偏,那要派上用場(chǎng)呀!那是在哪里用注射器把依賴注入了MainActivity呢弦讽。請(qǐng)看,我在MainActivity里面第2個(gè)注釋膀哲,inject()方法往产。沒(méi)錯(cuò)就是這個(gè)方法,在這個(gè)方法里面用DaggerCoffeeShopComponent.builder().build().inject(this);來(lái)實(shí)現(xiàn)了注入某宪。 等等仿村,這個(gè)DaggerCoffeeShopComponet是哪里來(lái)的? 大家還記得在配置Dagger2框架環(huán)境的時(shí)候兴喂,引入了APT的包嗎蔼囊,這個(gè)包是一個(gè)gradle插件焚志,用于結(jié)合注釋自動(dòng)生成代碼,所以這個(gè)包一定要配置畏鼓,否則不能自動(dòng)根據(jù)Dagger2的注釋來(lái)生成關(guān)鍵的代碼酱酬。想要了解APT的可以看看這篇文章android-apt。 所以DaggerCoffeeShopComponent就是一個(gè)自動(dòng)生成的實(shí)現(xiàn)了CoffeeShopComponent的類云矫。文件路徑是moudle路徑\build\generated\source\apt\debug\com\gotech\changelauncherbg\demodagger\DaggerCoffeeShopComponent膳沽,下面自動(dòng)生成的類都在這個(gè)路徑里面。當(dāng)然APT還根據(jù)注釋自動(dòng)生成了其他的代碼让禀。我們先分析這個(gè)挑社,因?yàn)檫@個(gè)是實(shí)現(xiàn)依賴注入的入口類。注意啦巡揍,自動(dòng)生成代碼痛阻,是要你執(zhí)行了rebuild project才會(huì)自動(dòng)生成的,所以呢你編寫(xiě)完代碼之后記得一定要rebuild才能得到這些類腮敌。

好吧阱当,下面就一起來(lái)看看DaggerCoffeeShopComponent是怎么把Coffee的實(shí)例,注入到mCoffee里面的缀皱。上代碼:

//說(shuō)明這段代碼時(shí)生成的斗这,并且生成自ComponetProcessor
@Generated("dagger.internal.codegen.ComponentProcessor")
public final class DaggerCoffeeShopComponent implements CoffeeShopComponent {
private MembersInjector<CoffeeShopActivity> coffeeShopActivityMembersInjector;

private DaggerCoffeeShopComponent(Builder builder) {  
  assert builder != null;
  initialize(builder);
}

public static Builder builder() {  
  return new Builder();
}

public static CoffeeShopComponent create() {  
  return builder().build();
}
// 初始化
private void initialize(final Builder builder) {  
  this.coffeeShopActivityMembersInjector = CoffeeShopActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), Coffee_Factory.create());
}
//重寫(xiě)inject方法,實(shí)現(xiàn)依賴注入
@Override
public void inject(CoffeeShopActivity coffeeShopActivity) {  
  coffeeShopActivityMembersInjector.injectMembers(coffeeShopActivity);
}

public static final class Builder {
  private Builder() {  
  }

  public CoffeeShopComponent build() {  
    return new DaggerCoffeeShopComponent(this);
  }
}
}

從上面的代碼可以知道啤斗,DaggerCoffeeComponent用有一個(gè)內(nèi)部建造類Builder表箭,可以看成一個(gè)簡(jiǎn)單的建造模式的應(yīng)用。利用Builder來(lái)建造一個(gè)DaggerCoffeeShopComponet對(duì)象然后利用CoffeeShopActivity_MembersInjector初始化coffeeShopActivityMembersInjector钮莲。這個(gè)是真正實(shí)現(xiàn)依賴注入的類免钻。從類名MembersInjector<CoffeeShopActivity> 可以看出這是一個(gè)用于注入成員變量的注入器,然后要注入的目標(biāo)類是CoffeeShopActivity崔拥。 接下來(lái)极舔,我們看看CoffeeShopActivity_MembersInjector這個(gè)類的代碼。

@Generated("dagger.internal.codegen.ComponentProcessor")
public final class CoffeeShopActivity_MembersInjector implements MembersInjector<CoffeeShopActivity> {
 private final MembersInjector<AppCompatActivity> supertypeInjector;
 private final Provider<Coffee> mCoffeeProvider;

 public CoffeeShopActivity_MembersInjector(MembersInjector<AppCompatActivity> supertypeInjector, Provider<Coffee> mCoffeeProvider) {  
   assert supertypeInjector != null;
   this.supertypeInjector = supertypeInjector;
   assert mCoffeeProvider != null;
   this.mCoffeeProvider = mCoffeeProvider;
 }

 @Override
 public void injectMembers(CoffeeShopActivity instance) {  
   if (instance == null) {
     throw new NullPointerException("Cannot inject members into a null reference");
   }
   supertypeInjector.injectMembers(instance);
   //1.獲取一個(gè)Coffee的實(shí)例链瓦,復(fù)制給CoffeeShopActivity的實(shí)例instance拆魏,從這里可以看出mCoffee不能是私有的。
   instance.mCoffee = mCoffeeProvider.get();
 }

 public static MembersInjector<CoffeeShopActivity> create(MembersInjector<AppCompatActivity> supertypeInjector, Provider<Coffee> mCoffeeProvider) {  
     return new CoffeeShopActivity_MembersInjector(supertypeInjector, mCoffeeProvider);
 }
}

上面代碼注釋處渤刃,就是實(shí)現(xiàn)注入的地方卖子,通過(guò)CoffeeProvider獲取一個(gè)Coffee對(duì)象洋闽,然后復(fù)制給CoffeeShopActivity對(duì)象的mCoffee成員變量诫舅。
跟蹤下來(lái),終于知道是在什么地方給要依賴的成員變量賦值的了铐伴。其實(shí)我們可以看出当宴,并不是沒(méi)有用到new ,只不過(guò)Dagger2通過(guò)自動(dòng)生成代碼户矢,幫你new了梯浪,你就省去了瓢娜,這個(gè)new的過(guò)程眠砾,直接可以用了褒颈。這個(gè)呢谷丸,只是一個(gè)簡(jiǎn)單的成員變量的依賴跟蹤刨疼,其他的通過(guò)module來(lái)提供依賴對(duì)象的例子揩慕,其實(shí)跟蹤路徑和這個(gè)大同小異漩绵。 我這里就以小見(jiàn)大的分析這么個(gè)小例子止吐,更復(fù)雜的用法如果有什么疑問(wèn)碍扔,歡迎留言交流不同。

總結(jié)

我的咖啡店開(kāi)好了二拐,咖啡都不用我自己去拿百新,自然有人給我送過(guò)來(lái)饭望,真是方便至極铅辞。干了這杯咖啡斟珊。最后,我做個(gè)簡(jiǎn)單的關(guān)鍵點(diǎn)總結(jié)吧!

  • 被依賴的成員變量的修飾符钩乍,不能是私有的怔锌。否則不能實(shí)現(xiàn)依賴注入涝涤。
  • 每次編寫(xiě)完代碼之后阔拳,記得rebuild project工程糊肠,自動(dòng)生成代碼货裹。
  • 在使用成員變量之前弧圆,一定要先注入依賴搔预,即編寫(xiě)一個(gè)類似于CoffeeShopActivityinject方法经伙。注入之后才能使用帕膜。
  • Component的接口里面的方法垮刹,參數(shù)類型一定要是目標(biāo)類荒典,不能是目標(biāo)類的父類。提供依賴的方法或者構(gòu)造函數(shù)遮咖,返回的類型也一定要是 要被依賴的類的類名御吞,不能是父類。

最后呢揍诽,雖然只是簡(jiǎn)單的一個(gè)成員變量的依賴注入的流程分析寝姿,但是其他復(fù)雜的依賴?yán)佣鋵?shí)看懂了這個(gè)根资,再分析其他的應(yīng)該也挺簡(jiǎn)單的,關(guān)鍵是了解了原理。希望大家多多指點(diǎn)鹰椒,哪里寫(xiě)的不對(duì)的,或者文章編寫(xiě)有什么建議的奸汇,都?xì)g迎大家留言告知我擂找。喜歡的在文末,輕輕點(diǎn)個(gè)贊哦柬采。o 謝謝!Have a nice day肩刃!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市崭添,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖蓝角,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件并徘,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)声畏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門科展,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)甘邀,“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵胸竞,是天一觀的道長(zhǎng)卫枝。 經(jīng)常有香客問(wèn)我,道長(zhǎng)讹挎,這世上最難降的妖魔是什么校赤? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮筒溃,結(jié)果婚禮上马篮,老公的妹妹穿的比我還像新娘。我一直安慰自己怜奖,他們只是感情好浑测,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著歪玲,像睡著了一般迁央。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上滥崩,一...
    開(kāi)封第一講書(shū)人閱讀 49,741評(píng)論 1 289
  • 那天岖圈,我揣著相機(jī)與錄音,去河邊找鬼夭委。 笑死幅狮,一個(gè)胖子當(dāng)著我的面吹牛募强,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播崇摄,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼擎值,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了逐抑?” 一聲冷哼從身側(cè)響起鸠儿,我...
    開(kāi)封第一講書(shū)人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎厕氨,沒(méi)想到半個(gè)月后进每,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡命斧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年田晚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片国葬。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡贤徒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出汇四,到底是詐尸還是另有隱情接奈,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布通孽,位于F島的核電站序宦,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏背苦。R本人自食惡果不足惜互捌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望糠惫。 院中可真熱鬧疫剃,春花似錦、人聲如沸硼讽。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)固阁。三九已至壤躲,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間备燃,已是汗流浹背碉克。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留并齐,地道東北人漏麦。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓客税,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親撕贞。 傳聞我的和親對(duì)象是個(gè)殘疾皇子更耻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,734評(píng)論 25 707
  • 前言 Dagger2 當(dāng)前Android流行的依賴注入框架。未來(lái)Android應(yīng)用的趨勢(shì)也許是MVP+Retrof...
    DorisSunny閱讀 1,323評(píng)論 0 3
  • 本文的分析基于dagger2的2.7版本捏膨。 谷歌開(kāi)發(fā)維護(hù)的Dagger2出來(lái)有很長(zhǎng)時(shí)間了秧均,目前在很多開(kāi)源項(xiàng)目上也能...
    sososeen09閱讀 13,593評(píng)論 31 108
  • ****(說(shuō)在最前:閱讀本篇之前,希望大家對(duì)Dagger2已經(jīng)有了一個(gè)初步的了解号涯。從而幫助感覺(jué)似是而非的同學(xué)進(jìn)一步...
    我是昵稱閱讀 911評(píng)論 3 6
  • 一直以來(lái)链快,我有大男子主義誉己,每次老婆說(shuō)我,我都是堅(jiān)定的否認(rèn)域蜗。但是夜深人靜時(shí)巫延,或者伏案寫(xiě)作時(shí),偶爾腦旱叵回蹦出:或許我是...
    小李非刀閱讀 1,648評(píng)論 5 2