Android Dagger2 從零單排(一) 基礎(chǔ)注解

??轉(zhuǎn)發(fā)請(qǐng)注明出處:http://www.reibang.com/p/7ee1a1100fab
??Dagger2作為Android界最具殺傷力的匕首,本系列文章將用最通俗的語言帶領(lǐng)你揭開它的真面目修档。
??邊緣OB:從零單排帶你從低分局打到高分局萧求,從First Blood(第一滴血)到Holy Shit(超越神的殺戮)姻乓,每盤Rampage(暴走)不在話下想幻!
??Android Dagger2 從零單排(一) 基礎(chǔ)注解
??Android Dagger2 從零單排(二) @Qualifier
??Android Dagger2 從零單排(三) @Scope
??Android Dagger2 從零單排(四) Dependencies與SubComponent

1.Dagger2簡(jiǎn)介

??"A fast dependency injector for Android and Java."
??Dagger2GitHub地址的首頁簡(jiǎn)介就這么一句話恋谭,Android和java的快速依賴注入场斑。簡(jiǎn)單述說就是組件只管依賴的使用漓踢,而依賴的具體實(shí)現(xiàn)交給容器去決定,這是DI(Dependency Injection)框架的核心思想漏隐。另外使用Dagger2不用擔(dān)心性能的消耗喧半,不使用反射,所有的注解均停留在編譯時(shí)期青责。

2.配置Dagger2:

dependencies {
    api 'com.google.dagger:dagger:2.x'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.x'
}

??注意:如果gradle版本低于2.2挺据,需要使用apt插件,Kotlin寫法也有點(diǎn)脖隶。

3.注解的分類:

??在描述注解的作用前扁耐,我們先看dagger2最簡(jiǎn)單的例子,
??例子一产阱,假設(shè)領(lǐng)導(dǎo)下午要出去視察民情婉称,需要一輛公交車,司機(jī)就不用請(qǐng)了构蹬,領(lǐng)導(dǎo)做表率自己開王暗,小秘把領(lǐng)導(dǎo)的指示告訴了車場(chǎng)調(diào)度員。
??找輛公交車要停放在停車場(chǎng)(Bus要注入到ParkingActivity)庄敛,停車場(chǎng)不管公交車按什么路線停車(ParkingActivity不管Bus是如何注入的)俗壹,車場(chǎng)調(diào)度員會(huì)負(fù)責(zé)好管理(Dagger2容器會(huì)將Bus的注入到ParkingActivity)。
??DaggerParkingComponent類是編譯過后Dagger2自動(dòng)生成的藻烤,是ParkingComponent的實(shí)現(xiàn)類绷雏,可以說DaggerParkingComponent就是實(shí)際的車場(chǎng)調(diào)度員,ParkingComponent是對(duì)車場(chǎng)調(diào)度員的約束怖亭,在onCreate方法完成了注入過程之众。

public class Bus {
    @Inject
    public Bus() {
    }
}

public class ParkingActivity extends Activity {
    @Inject
    Bus mBus;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_dagger);
        DaggerParkingComponent.create().inject(this);//DaggerParkingComponent類需要編譯才會(huì)生成
        ((TextView) findViewById(R.id.text)).setText(mBus.toString());
    }
}

@Component
public interface ParkingComponent {
    void inject(ParkingActivity activity);
}

@Inject注解:
??(1)注解在屬性中表示該屬性需要依賴注入,不能使用private修飾依许,示例代碼表示需要注入屬性mBus(Bus的車位):

    @Inject
    Bus mBus;

??(2)注解在方法中表示該方法需要依賴注入棺禾,不能是抽象方法,不能使用private修飾峭跳,示例代碼表示需要注入方法injectBus:

    //@Inject
    Bus mBus;
    @Inject
    public void injectBus(Bus bus) {
        mBus = bus;
    }

??方法注入的參數(shù)同樣由Dagger2容器提供膘婶,以上代碼的目的與第一點(diǎn)介紹的屬性注入一樣缺前,都是為了注入mBus,如果目的是注入屬性的話悬襟,方法注入和屬性注入基本沒有區(qū)別衅码,屬性注入是Dagger2中使用最多的一個(gè)注入方式。
??那么什么情況下應(yīng)該使用方法注入脊岳?比如依賴需要this對(duì)象的時(shí)候逝段,方法注入可以提供安全的this對(duì)象。
??注意割捅,Dagger2容器先調(diào)用屬性注入奶躯,然后再方法注入,若把示例代碼mBus的@Inject取消注釋亿驾,此時(shí)mBus會(huì)注入2次嘹黔,并且兩次注入的Bus也不相同。
??(3)注解在構(gòu)造方法中表示此類能為Dagger2提供依賴關(guān)系莫瞬,Dagger2可以使用這個(gè)構(gòu)造方法構(gòu)建對(duì)象(Bus的來歷):

    @Inject
    public Bus() {
    }

??如果有多個(gè)構(gòu)造函數(shù)儡蔓,只能注解一個(gè),否則編譯報(bào)錯(cuò)疼邀,多構(gòu)造方法的方式下一篇會(huì)介紹喂江。
@Component注解:
??一般用來注解接口,被注解的接口在編譯時(shí)會(huì)生成相應(yīng)的實(shí)例旁振,實(shí)例名稱一般以Dagger為前綴开呐,作為所需注入依賴(ParkingActivity的mBus屬性)和提供依賴(Bus類構(gòu)造方法)之間的橋梁,把提供的依賴(Bus)注入到所需注入的依賴中(ParkingActivity的mBus屬性)规求。
??通俗說,就是Dagger2的容器卵惦,在例子中是車場(chǎng)調(diào)度員阻肿,把公交車和停車場(chǎng)聯(lián)系在一起。車場(chǎng)調(diào)度員知道停車場(chǎng)要準(zhǔn)備一輛公交車沮尿,停車場(chǎng)不需要知道車是哪里來的丛塌,也不需要知道怎么停,車場(chǎng)調(diào)度員找好車后畜疾,停在車位上就完事赴邻,等候領(lǐng)導(dǎo)用車就可以了。
??例子一總結(jié)啡捶,兩個(gè)@Inject注解形成了依賴關(guān)系姥敛,@Component作為連接這個(gè)關(guān)系的橋梁存在,尋找到依賴并且注入瞎暑,并且注入與被注入之間互不干涉彤敛,經(jīng)過編譯@Component生成Dagger為前綴的實(shí)例与帆,調(diào)用實(shí)例的方法注入。

??例子二墨榄,領(lǐng)導(dǎo)想著不妥玄糟,自己沒開過公交車掂器,為保險(xiǎn)起見還是趕緊吩咐小秘刻像,去給配個(gè)公交車司機(jī)宝恶,小秘自然跟車場(chǎng)調(diào)度員說了拥诡。
??車場(chǎng)調(diào)度員一想播歼,只是比之前多了一個(gè)步驟佣耐,給公交車配置一個(gè)司機(jī)(Bus類添加String類型Driver構(gòu)造方法)比然。于是打電話給開公交車的隔壁老王舔庶,老王自然是應(yīng)諾了下來猪狈,于是乎箱沦,對(duì)例子一的代碼做一下修改。

public class Bus {
    private String driver;
    @Inject
    public Bus(String driver) {
        this.driver = driver;
    }
}

public class ParkingActivity extends Activity {
    @Inject
    Bus mBus;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_dagger);
        DaggerParkingComponent.create().inject(this);//DaggerParkingComponent類需要編譯才會(huì)生成
        ((TextView) findViewById(R.id.text)).setText(mBus.toString());//重寫B(tài)us的toString()方法能看到打印出"隔壁老王"雇庙,注入成功
    }
}

@Component(modules = ParkingModule.class)
public interface ParkingComponent {
    void inject(ParkingActivity activity);
}

@Module
public class ParkingModule {
    public ParkingModule() {
    }
    @Provides
    public String provideDriver() {
        return "隔壁老王";
    }
}

@Module注解:
??該注解與@Provides結(jié)合為Dagger2提供依賴關(guān)系谓形,對(duì)上文@Inject第三點(diǎn)的補(bǔ)充,用于不能用@Inject提供依賴的地方疆前,如第三方庫(kù)提供的類寒跳,基本數(shù)據(jù)類型等不能修改源碼的情況。
@Provides注解:
??@Provides僅能注解方法竹椒,且方法所在類要有@Module注解童太。注解后的方法表示Dagger2能用該方法實(shí)例對(duì)象提供依賴。按照慣例胸完,@Provides方法的命名以provide為前綴书释,方便閱讀管理。
??例子二總結(jié)赊窥,首先@Component注解包含了一個(gè)ParkingModule類爆惧,表示Dagger2可以從ParkingModule類查找依賴,Dagger2會(huì)自動(dòng)查找ParkingModule類有@Provides注釋的方法實(shí)例依賴锨能,最后完成注入
??注意1扯再,如果在ParkingModule里面同樣提供Bus的依賴,Dagger2會(huì)優(yōu)先在@Module注解的類上查找依賴址遇,沒有的情況才會(huì)去查詢類的@Inject構(gòu)造方法熄阻,如下面的代碼,則Bus的司機(jī)就是小王而不是老王了倔约。

@Module
public class ParkingModule {
    public ParkingModule() {
    }
    @Provides
    public String provideDriver() {
        return "隔壁老王";
    }
    @Provides
    public Bus provideBus() {
        return new Bus("樓上小王");
    }
}

??注意2秃殉,@Module類可以從構(gòu)造方法傳入依賴,@Provides方法也可以有依賴關(guān)系。
??@Provides方法也有依賴關(guān)系的情況复濒,Dagger2會(huì)繼續(xù)查找可以提供依賴的方法脖卖,類似于一種遞歸的狀態(tài),一步一步返回實(shí)例巧颈。如下代碼畦木,ParkingModule構(gòu)造方法傳入driver為provideDriver方法提供依賴返回,provideDriver返回driver作為provideBus方法的依賴實(shí)例Bus砸泛。
??ParkingModule加入有參構(gòu)造方法后十籍,調(diào)用方式也需要變成,現(xiàn)在司機(jī)就變成了樓下老李了唇礁。

@Module
public class ParkingModule {
    private String driver;
    public ParkingModule(String driver) {
        this.driver = driver;
    }
    @Provides
    public String provideDriver() {
        return driver;
    }
    @Provides
    public Bus provideBus(String driver) {
        return new Bus(driver);
    }
}
    //調(diào)用方式改變
    DaggerParkingComponent.builder().parkingModule(new ParkingModule("樓下老李")).build().inject(this);

關(guān)于注入方法的疑惑:
??初次接觸Dagger2時(shí)勾栗,會(huì)發(fā)現(xiàn)每次Build之后,create()方法時(shí)有時(shí)無盏筐,其實(shí)create()方法是簡(jiǎn)化注入流程而設(shè)計(jì)的围俘,點(diǎn)進(jìn)去看源碼實(shí)際上是在內(nèi)部幫你調(diào)用了。

  public static MainComponent create() {
    return new Builder().build();
  }

以下情況都會(huì)生成create()方法:
??(1)@Component注解接口沒有聲明任何Module琢融,這種情況自然不必多說界牡。
??(2)@Component注解接口聲明了Module,沒有使用Module提供的依賴漾抬,無論Module構(gòu)造方法是否有參宿亡,這種情況@Component注解生成的Java文件也有提示:

    /**大約意思就是你聲明了Module,但component沒有用到里面的實(shí)例纳令,實(shí)例Module是多余無用的操作挽荠。
     * @deprecated This module is declared, but an instance is not used in the component. This
     *     method is a no-op. For more, see https://google.github.io/dagger/unused-modules.
     */

??(3)@Component注解接口聲明了Module,使用了Module提供的依賴平绩,Module構(gòu)造方法沒有參數(shù)圈匆,點(diǎn)進(jìn)去看源碼實(shí)際上是在內(nèi)部初始化了Module。

    public MainComponent build() {
      if (mainModule == null) {
        this.mainModule = new MainModule();
      }
      return new DaggerMainComponent(this);
    }

下面這種是一定不會(huì)有create()方法出現(xiàn):
??(1)@Component注解接口聲明了Module捏雌,使用了Module提供的依賴跃赚,Module構(gòu)造方法有參數(shù),無論你是否使用了該參數(shù)作為依賴腹忽,這時(shí)候注入都需要初始化Module才能注入成功,看源碼如果不初始化Module會(huì)直接報(bào)異常砚作。

    public MainComponent build() {
      if (mainModule == null) {
        throw new IllegalStateException(MainModule.class.getCanonicalName() + " must be set");
      }
      return new DaggerMainComponent(this);
    }

??開始接觸時(shí)create()方法可以作為檢測(cè)手段窘奏,例如聲明了Module,且Module構(gòu)造方法有參數(shù)葫录,如果有create()方法着裹,表明此時(shí)沒使用Module提供的依賴,可以在Module查找下原因米同。實(shí)際項(xiàng)目運(yùn)用中骇扇,create()方法比較少使用摔竿,一般Module都會(huì)傳參。

最后總結(jié)了一下依賴注入流程:
1:查找Module中是否有該實(shí)例的@Provides方法少孝。
??1.1:有继低,走第2點(diǎn)。
??1.2:沒有稍走,查找該實(shí)例是否有@Inject構(gòu)造方法袁翁。
????1.1.1:有,走第3點(diǎn)婿脸。
????1.1.2:沒有粱胜,注入失敗。
2:@Provides方法是否有參數(shù)
??2.1:有狐树,則回到第1點(diǎn)查找每個(gè)參數(shù)的依賴
??2.2:沒有焙压,實(shí)例該類返回一次依賴
3:@Inject構(gòu)造方法是否有參數(shù)
??3.1:有,則回到第1點(diǎn)查找每個(gè)參數(shù)的依賴
??3.2:沒有抑钟,實(shí)例該類返回一次依賴
4:以上流程遞歸返回注入目標(biāo)的所有依賴涯曲,最后依賴注入。

??Demo源碼截我 對(duì)應(yīng)daggerOne包名
??Dagger2 GitHub地址
??Dagger2 官網(wǎng)地址
??所有的測(cè)試實(shí)例均基于2.15版本味赃。
??下一篇掀抹,我們來研究多構(gòu)造方法與多個(gè)@Provides方法返回同一數(shù)據(jù)類型的情況:@Qualifier注解。

最后編輯于
?著作權(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)離奇詭異狠持,居然都是意外死亡疟位,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門喘垂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來甜刻,“玉大人,你說我怎么就攤上這事正勒〉迷海” “怎么了?”我有些...
    開封第一講書人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵章贞,是天一觀的道長(zhǎng)祥绞。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么蜕径? 我笑而不...
    開封第一講書人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任两踏,我火速辦了婚禮,結(jié)果婚禮上兜喻,老公的妹妹穿的比我還像新娘梦染。我一直安慰自己,他們只是感情好虹统,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開白布弓坞。 她就那樣靜靜地躺著,像睡著了一般车荔。 火紅的嫁衣襯著肌膚如雪渡冻。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,741評(píng)論 1 289
  • 那天忧便,我揣著相機(jī)與錄音族吻,去河邊找鬼。 笑死珠增,一個(gè)胖子當(dāng)著我的面吹牛超歌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蒂教,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼巍举,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了凝垛?” 一聲冷哼從身側(cè)響起懊悯,我...
    開封第一講書人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎梦皮,沒想到半個(gè)月后炭分,有當(dāng)?shù)厝嗽跇淞掷锇l(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
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望虽界。 院中可真熱鬧汽烦,春花似錦、人聲如沸莉御。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽礁叔。三九已至牍颈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間琅关,已是汗流浹背煮岁。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(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