成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專(zhuān)欄INFORMATION COLUMN

神兵利器Dagger2

_DangJin / 1090人閱讀

摘要:方案我們手動(dòng)以構(gòu)造函數(shù)的方式注入依賴(lài),將和作為參數(shù)傳入而不是在的構(gòu)造函數(shù)中去顯示的創(chuàng)建。同樣我們需要在類(lèi)的成員變量上加上表示自己需要為自己提供依賴(lài)類(lèi)的構(gòu)造函數(shù)上的也需要去掉,應(yīng)為現(xiàn)在不需要通過(guò)構(gòu)造函數(shù)上的來(lái)提供依賴(lài)了。

Dagger-匕首,鼎鼎大名的Square公司旗下又一把利刃(沒(méi)錯(cuò)!還有一把黃油刀,喚作ButterKnife);故此給本篇取名神兵利器Dagger2。

Dagger2起源于Dagger,是一款基于Java注解來(lái)實(shí)現(xiàn)的完全在編譯階段完成依賴(lài)注入的開(kāi)源庫(kù),主要用于模塊間解耦、提高代碼的健壯性和可維護(hù)性。Dagger2在編譯階段通過(guò)apt利用Java注解自動(dòng)生成Java代碼,然后結(jié)合手寫(xiě)的代碼來(lái)自動(dòng)幫我們完成依賴(lài)注入的工作。

起初Square公司受到Guice的啟發(fā)而開(kāi)發(fā)了Dagger,但是Dagger這種半靜態(tài)半運(yùn)行時(shí)的框架還是有些性能問(wèn)題(雖說(shuō)依賴(lài)注入是完全靜態(tài)的,但是其有向無(wú)環(huán)圖(Directed Acyclic Graph)還是基于反射來(lái)生成的,這無(wú)論在大型的服務(wù)端應(yīng)用還是在A(yíng)ndroid應(yīng)用上都不是最優(yōu)方案)。因此Google工程師Fork了Dagger項(xiàng)目,對(duì)它進(jìn)行了改造。于是變演變出了今天我們要討論的Dagger2,所以說(shuō)Dagger2其實(shí)就是高配版的Dagger。

依賴(lài)注入(Dependency Injection)

那么什么是依賴(lài)注入呢?在解釋這個(gè)概念前我們先看一小段代碼:

public class Car{

    private Engine engine;
    
    public Car(){
        engine = new Engine();
    }
}

這段Java代碼中Car類(lèi)持有了對(duì)Engine實(shí)例的引用,我們稱(chēng)之為Car類(lèi)對(duì)Engine類(lèi)有一個(gè)依賴(lài)。而依賴(lài)注入則是指通過(guò)注入的方式實(shí)現(xiàn)類(lèi)與類(lèi)之間的依賴(lài),下面是常見(jiàn)的三種依賴(lài)注入的方式:

1、構(gòu)造注入:通過(guò)構(gòu)造函數(shù)傳參給依賴(lài)的成員變量賦值,從而實(shí)現(xiàn)注入。
public class Car{

    private Engine engine;
    
    public Car(Engine engine){
        this.engine = engine;
    }
}
2、接口注入:實(shí)現(xiàn)接口方法,同樣以傳參的方式實(shí)現(xiàn)注入。
public interface Injection{

    void inject(T t);
}

public class Car implements Injection{

    private Engine engine;
    
    public Car(){}

    public void inject(Engine engine){
        this.engine = engine;
    }

}
3、注解注入:使用Java注解在編譯階段生成代碼實(shí)現(xiàn)注入或者是在運(yùn)行階段通過(guò)反射實(shí)現(xiàn)注入。
public class Car{

    @Inject
    Engine engine;
    
    public Car(){}
}

前兩種注入方式需要我們編寫(xiě)大量的模板代碼,而機(jī)智的Dagger2則是通過(guò)Java注解在編譯期來(lái)實(shí)現(xiàn)依賴(lài)注入的。

為什么需要依賴(lài)注入

我們之所是要依賴(lài)注入,最重要的就是為了解耦,達(dá)到高內(nèi)聚低耦合的目的,保證代碼的健壯性、靈活性和可維護(hù)性。

下面我們看看同一個(gè)業(yè)務(wù)的兩種實(shí)現(xiàn)方案:

1、方案A
public class Car{

    private Engine engine;
    private List wheels;

    public Car(){
        engine = new Engine();
        wheels = new ArrayList<>();
        for(int i = 0; i < 4; i++){
            wheels.add(new Wheel());
        }
    }

    public void start{
        System.out.println("啟動(dòng)汽車(chē)");
    }
}

public class CarTest{

    public static void main(String[] args){
        Car car = new Car();
        car.start();
    }
} 
2、方案B
public class Car{

    private Engine engine;
    private List wheels;

    public Car(Engine engine, List wheels){
        this.engine = engine;
        this.wheels = wheels;
    }

    public void start{
        System.out.println("啟動(dòng)汽車(chē)");
    }
}

public class CarTest{

    public static void main(String[] args){

        Engine engine = new Engine();
        List wheels = new ArrayList<>();
        for(int i = 0; i < 4; i++){
            wheels.add(new Wheel());
        }
        Car car = new Car(engine, wheels);
        car.start();
    }
}

方案A:由于沒(méi)有依賴(lài)注入,因此需要我們自己是在Car的構(gòu)造函數(shù)中創(chuàng)建Engine和Wheel對(duì)象。

方案B:我們手動(dòng)以構(gòu)造函數(shù)的方式注入依賴(lài),將engine和wheels作為參數(shù)傳入而不是在Car的構(gòu)造函數(shù)中去顯示的創(chuàng)建。

方案A明顯喪失了靈活性,一切依賴(lài)都是在Car類(lèi)的內(nèi)部創(chuàng)建,Car與Engine和Wheel嚴(yán)重耦合。一旦Engine或者Wheel的創(chuàng)建方式發(fā)生了改變,我們就必須要去修改Car類(lèi)的構(gòu)造函數(shù)(比如說(shuō)現(xiàn)在創(chuàng)建Wheel實(shí)例的構(gòu)造函數(shù)改變了,需要傳入Rubber(橡膠)了);另外我們也沒(méi)辦法替換動(dòng)態(tài)的替換依賴(lài)實(shí)例(比如我們想把Car的Wheel(輪胎)從鄧祿普(輪胎品牌)換成米其林(輪胎品牌)的)。這類(lèi)問(wèn)題在大型的商業(yè)項(xiàng)目中則更加嚴(yán)重,往往A依賴(lài)B、B依賴(lài)C、C依賴(lài)D、D依賴(lài)E;一旦稍有改動(dòng)便牽一發(fā)而動(dòng)全身,想想都可怕!而依賴(lài)注入則很好的幫我們解決了這一問(wèn)題。

為什么是Dagger2

無(wú)論是構(gòu)造函數(shù)注入還是接口注入,都避免不了要編寫(xiě)大量的模板代碼。機(jī)智的猿猿們當(dāng)然不開(kāi)心做這些重復(fù)性的工作,于是各種依賴(lài)注入框架應(yīng)用而生。但是這么多的依賴(lài)注入框架為什么我們卻偏愛(ài)Dagger2呢?我們先從Spring中的控制反轉(zhuǎn)(IOC)說(shuō)起。

談起依賴(lài)注入,做過(guò)J2EE開(kāi)發(fā)的同學(xué)一定會(huì)想起Spring IOC,那通過(guò)迷之XML來(lái)配置依賴(lài)的方式真的很讓人討厭;而且XML與Java代碼分離也導(dǎo)致代碼鏈難以追蹤。之后更加先進(jìn)的Guice(Android端也有個(gè)RoboGuice)出現(xiàn)了,我們不再需要通過(guò)XML來(lái)配置依賴(lài),但其運(yùn)行時(shí)實(shí)現(xiàn)注入的方式讓我們?cè)谧粉櫤投ㄎ诲e(cuò)誤的時(shí)候卻又萬(wàn)分痛苦。開(kāi)篇提到過(guò)Dagger就是受Guice的啟發(fā)而開(kāi)發(fā)出來(lái)的;Dagger繼承了前輩的思想,在性能又碾壓了它的前輩Guice,可謂是長(zhǎng)江后浪推前浪,前浪死在沙灘上。

又如開(kāi)篇我在簡(jiǎn)介中說(shuō)到的,Dagger是一種半靜態(tài)半運(yùn)行時(shí)的DI框架,雖說(shuō)依賴(lài)注入是完全靜態(tài)的,但是生成有向無(wú)環(huán)圖(DAG)還是基于反射來(lái)實(shí)現(xiàn),這無(wú)論在大型的服務(wù)端應(yīng)用還是在A(yíng)ndroid應(yīng)用上都不是最優(yōu)方案。升級(jí)版的Dagger2解決了這一問(wèn)題,從半靜態(tài)變?yōu)橥耆o態(tài),從Map式的API變成申明式API(@Module),生成的代碼更優(yōu)雅高效;而且一旦出錯(cuò)我們?cè)诰幾g期間就能發(fā)現(xiàn)。所以Dagger2對(duì)開(kāi)發(fā)者的更加友好了,當(dāng)然Dagger2也因此喪失了一些靈活性,但總體來(lái)說(shuō)利還是遠(yuǎn)遠(yuǎn)大于弊的。

前面提到這種A B C D E連續(xù)依賴(lài)的問(wèn)題,一旦E的創(chuàng)建方式發(fā)生了改變就會(huì)引發(fā)連鎖反應(yīng),可能會(huì)導(dǎo)致A B C D都需要做針對(duì)性的修改;但是騷年,你以為為這僅僅是工作量的問(wèn)題嗎?更可怕的是我們創(chuàng)建A時(shí)需要按順序先創(chuàng)建E D C B四個(gè)對(duì)象,而且必須保證順序上是正確的。Dagger2就很好的解決了這一問(wèn)題(不只是Dagger2,在其他DI框架中開(kāi)發(fā)者同樣不需要關(guān)注這些問(wèn)題)。

Dagger2注解

開(kāi)篇我們就提到Dagger2是基于Java注解來(lái)實(shí)現(xiàn)依賴(lài)注入的,那么在正式使用之前我們需要先了解下Dagger2中的注解。Dagger2使用過(guò)程中我們通常接觸到的注解主要包括:@Inject, @Module, @Provides, @Component, @Qulifier, @Scope, @Singleten。

@Inject:@Inject有兩個(gè)作用,一是用來(lái)標(biāo)記需要依賴(lài)的變量,以此告訴Dagger2為它提供依賴(lài);二是用來(lái)標(biāo)記構(gòu)造函數(shù),Dagger2通過(guò)@Inject注解可以在需要這個(gè)類(lèi)實(shí)例的時(shí)候來(lái)找到這個(gè)構(gòu)造函數(shù)并把相關(guān)實(shí)例構(gòu)造出來(lái),以此來(lái)為被@Inject標(biāo)記了的變量提供依賴(lài);

@Module:@Module用于標(biāo)注提供依賴(lài)的類(lèi)。你可能會(huì)有點(diǎn)困惑,上面不是提到用@Inject標(biāo)記構(gòu)造函數(shù)就可以提供依賴(lài)了么,為什么還需要@Module?很多時(shí)候我們需要提供依賴(lài)的構(gòu)造函數(shù)是第三方庫(kù)的,我們沒(méi)法給它加上@Inject注解,又比如說(shuō)提供以來(lái)的構(gòu)造函數(shù)是帶參數(shù)的,如果我們之所簡(jiǎn)單的使用@Inject標(biāo)記它,那么他的參數(shù)又怎么來(lái)呢?@Module正是幫我們解決這些問(wèn)題的。

@Provides:@Provides用于標(biāo)注Module所標(biāo)注的類(lèi)中的方法,該方法在需要提供依賴(lài)時(shí)被調(diào)用,從而把預(yù)先提供好的對(duì)象當(dāng)做依賴(lài)給標(biāo)注了@Inject的變量賦值;

@Component:@Component用于標(biāo)注接口,是依賴(lài)需求方和依賴(lài)提供方之間的橋梁。被Component標(biāo)注的接口在編譯時(shí)會(huì)生成該接口的實(shí)現(xiàn)類(lèi)(如果@Component標(biāo)注的接口為CarComponent,則編譯期生成的實(shí)現(xiàn)類(lèi)為DaggerCarComponent),我們通過(guò)調(diào)用這個(gè)實(shí)現(xiàn)類(lèi)的方法完成注入;

@Qulifier:@Qulifier用于自定義注解,也就是說(shuō)@Qulifier就如同Java提供的幾種基本元注解一樣用來(lái)標(biāo)記注解類(lèi)。我們?cè)谑褂聾Module來(lái)標(biāo)注提供依賴(lài)的方法時(shí),方法名我們是可以隨便定義的(雖然我們定義方法名一般以provide開(kāi)頭,但這并不是強(qiáng)制的,只是為了增加可讀性而已)。那么Dagger2怎么知道這個(gè)方法是為誰(shuí)提供依賴(lài)呢?答案就是返回值的類(lèi)型,Dagger2根據(jù)返回值的類(lèi)型來(lái)決定為哪個(gè)被@Inject標(biāo)記了的變量賦值。但是問(wèn)題來(lái)了,一旦有多個(gè)一樣的返回類(lèi)型Dagger2就懵逼了。@Qulifier的存在正式為了解決這個(gè)問(wèn)題,我們使用@Qulifier來(lái)定義自己的注解,然后通過(guò)自定義的注解去標(biāo)注提供依賴(lài)的方法和依賴(lài)需求方(也就是被@Inject標(biāo)注的變量),這樣Dagger2就知道為誰(shuí)提供依賴(lài)了。----一個(gè)更為精簡(jiǎn)的定義:當(dāng)類(lèi)型不足以鑒別一個(gè)依賴(lài)的時(shí)候,我們就可以使用這個(gè)注解標(biāo)示;

@Scope:@Scope同樣用于自定義注解,我能可以通過(guò)@Scope自定義的注解來(lái)限定注解作用域,實(shí)現(xiàn)局部的單例;

@Singleton:@Singleton其實(shí)就是一個(gè)通過(guò)@Scope定義的注解,我們一般通過(guò)它來(lái)實(shí)現(xiàn)全局單例。但實(shí)際上它并不能提前全局單例,是否能提供全局單例還要取決于對(duì)應(yīng)的Component是否為一個(gè)全局對(duì)象。

我們提到@Inject和@Module都可以提供依賴(lài),那如果我們即在構(gòu)造函數(shù)上通過(guò)標(biāo)記@Inject提供依賴(lài),有通過(guò)@Module提供依賴(lài)Dagger2會(huì)如何選擇呢?具體規(guī)則如下:

步驟1:首先查找@Module標(biāo)注的類(lèi)中是否存在提供依賴(lài)的方法。

步驟2:若存在提供依賴(lài)的方法,查看該方法是否存在參數(shù)。

a:若存在參數(shù),則按從步驟1開(kāi)始依次初始化每個(gè)參數(shù);

b:若不存在,則直接初始化該類(lèi)實(shí)例,完成一次依賴(lài)注入。

步驟3:若不存在提供依賴(lài)的方法,則查找@Inject標(biāo)注的構(gòu)造函數(shù),看構(gòu)造函數(shù)是否存在參數(shù)。

a:若存在參數(shù),則從步驟1開(kāi)始依次初始化每一個(gè)參數(shù)

b:若不存在,則直接初始化該類(lèi)實(shí)例,完成一次依賴(lài)注入。

Dagger2使用入門(mén)

前面長(zhǎng)篇大論的基本都在介紹概念,下面我們看看Dagger2的基本應(yīng)用。關(guān)于Dagger2的依賴(lài)配置就不在這里占用篇幅去描述了,大家可以到它的github主頁(yè)下去查看官方教程https://github.com/google/dagger。接下來(lái)我們還是拿前面的Car和Engine來(lái)舉例。

1、案例A

Car類(lèi)是需求依賴(lài)方,依賴(lài)了Engine類(lèi);因此我們需要在類(lèi)變量Engine上添加@Inject來(lái)告訴Dagger2來(lái)為自己提供依賴(lài)。

public class Car {

    @Inject
    Engine engine;

    public Car() {
        DaggerCarComponent.builder().build().inject(this);
    }

    public Engine getEngine() {
        return this.engine;
    }
}

Engine類(lèi)是依賴(lài)提供方,因此我們需要在它的構(gòu)造函數(shù)上添加@Inject

public class Engine {
    
    @Inject
    Engine(){}
    
    public void run(){
        System.out.println("引擎轉(zhuǎn)起來(lái)了~~~");
    }
}

接下來(lái)我們需要?jiǎng)?chuàng)建一個(gè)用@Component標(biāo)注的接口CarComponent,這個(gè)CarComponent其實(shí)就是一個(gè)注入器,這里用來(lái)將Engine注入到Car中。

@Component
public interface CarComponent {
    void inject(Car car);
}

完成這些之后我們需要Build下項(xiàng)目,讓Dagger2幫我們生成相關(guān)的Java類(lèi)。接著我們就可以在Car的構(gòu)造函數(shù)中調(diào)用Dagger2生成的DaggerCarComponent來(lái)實(shí)現(xiàn)注入(這其實(shí)在前面Car類(lèi)的代碼中已經(jīng)有了體現(xiàn))

public Car() {
    DaggerCarComponent.builder().build().inject(this);
}
2、案例B

如果創(chuàng)建Engine的構(gòu)造函數(shù)是帶參數(shù)的呢?比如說(shuō)制造一臺(tái)引擎是需要齒輪(Gear)的?;蛘逧ggine類(lèi)是我們無(wú)法修改的呢?這時(shí)候就需要@Module和@Provide上場(chǎng)了。

同樣我們需要在Car類(lèi)的成員變量Engine上加上@Inject表示自己需要Dagger2為自己提供依賴(lài);Engine類(lèi)的構(gòu)造函數(shù)上的@Inject也需要去掉,應(yīng)為現(xiàn)在不需要通過(guò)構(gòu)造函數(shù)上的@Inject來(lái)提供依賴(lài)了。

public class Car {

    @Inject
    Engine engine;

    public Car() {
        DaggerCarComponent.builder().markCarModule(new MarkCarModule())
                .build().inject(this);
    }

    public Engine getEngine() {
        return this.engine;
    }
}

接著我們需要一個(gè)Module類(lèi)來(lái)生成依賴(lài)對(duì)象。前面介紹的@Module就是用來(lái)標(biāo)準(zhǔn)這個(gè)類(lèi)的,而@Provide則是用來(lái)標(biāo)注具體提供依賴(lài)對(duì)象的方法(這里有個(gè)不成文的規(guī)定,被@Provide標(biāo)注的方法命名我們一般以provide開(kāi)頭,這并不是強(qiáng)制的但有益于提升代碼的可讀性)。

@Module
public class MarkCarModule {

    public MarkCarModule(){ }

    @Provides Engine provideEngine(){
        return new Engine("gear");
    }
}

接下來(lái)我們還需要對(duì)CarComponent進(jìn)行一點(diǎn)點(diǎn)修改,之前的@Component注解是不帶參數(shù)的,現(xiàn)在我們需要加上modules = {MarkCarModule.class},用來(lái)告訴Dagger2提供依賴(lài)的是MarkCarModule這個(gè)類(lèi)。

@Component(modules = {MarkCarModule.class})
public interface CarComponent {
    void inject(Car car);
}

Car類(lèi)的構(gòu)造函數(shù)我們也需要修改,相比之前多了個(gè)markCarModule(new MarkCarModule())方法,這就相當(dāng)于告訴了注入器DaggerCarComponentMarkCarModule提供的依賴(lài)注入到了Car類(lèi)中。

public Car() {
   DaggerCarComponent.builder()
           .markCarModule(new MarkCarModule())
           .build().inject(this);
}

這樣一個(gè)最最基本的依賴(lài)注入就完成了,接下來(lái)我們測(cè)試下我們的代碼。

public static void main(String[] args){
    Car car = new Car();
    car.getEngine().run();
}

輸出

引擎轉(zhuǎn)起來(lái)了~~~
3、案例C

那么如果一臺(tái)汽車(chē)有兩個(gè)引擎(也就是說(shuō)Car類(lèi)中有兩個(gè)Engine變量)怎么辦呢?沒(méi)關(guān)系,我們還有@Qulifier!首先我們需要使用Qulifier定義兩個(gè)注解:

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface QualifierA { }
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface QualifierB { }

同時(shí)我們需要對(duì)依賴(lài)提供方做出修改

@Module
public class MarkCarModule {

    public MarkCarModule(){ }

    @QualifierA
    @Provides
    Engine provideEngineA(){
        return new Engine("gearA");
    }

    @QualifierB
    @Provides
    Engine provideEngineB(){
        return new Engine("gearB");
    }
}

接下來(lái)依賴(lài)需求方Car類(lèi)同樣需要修改

public class Car {

    @QualifierA @Inject Engine engineA;
    @QualifierB @Inject Engine engineB;

    public Car() {
        DaggerCarComponent.builder().markCarModule(new MarkCarModule())
                .build().inject(this);
    }

    public Engine getEngineA() {
        return this.engineA;
    }

    public Engine getEngineB() {
        return this.engineB;
    }
}

最后我們?cè)賹?duì)Engine類(lèi)做些調(diào)整方便測(cè)試

public class Engine {

    private String gear;
    
    public Engine(String gear){
        this.gear = gear;
    }
    
    public void printGearName(){
        System.out.println("GearName:" + gear);
    }
}

測(cè)試代碼

public static void main(String[] args) {
    Car car = new Car();
    car.getEngineA().printGearName();
    car.getEngineB().printGearName();
}

執(zhí)行結(jié)果:

GearName:gearA
GearName:gearB
4、案例D

接下來(lái)我們看看@Scope是如何限定作用域,實(shí)現(xiàn)局部單例的。

首先我們需要通過(guò)@Scope定義一個(gè)CarScope注解:

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface CarScope {
}

接著我們需要用這個(gè)@CarScope去標(biāo)記依賴(lài)提供方MarkCarModule。

@Module
public class MarkCarModule {

    public MarkCarModule() {
    }

    @Provides
    @CarScope
    Engine provideEngine() {
        return new Engine("gear");
    }
}

同時(shí)還需要使用@Scope去標(biāo)注注入器Compoent

@CarScope
@Component(modules = {MarkCarModule.class})
public interface CarComponent {
    void inject(Car car);
}

為了便于測(cè)試我們對(duì)Car和Engine類(lèi)做了一些改造:

public class Car {

    @Inject Engine engineA;
    @Inject Engine engineB;

    public Car() {
        DaggerCarComponent.builder()
                .markCarModule(new MarkCarModule())
                .build().inject(this);
    }
}
public class Engine {

    private String gear;
    
    public Engine(String gear){
        System.out.println("Create Engine");
        this.gear = gear;
    }
}

如果我們不適用@Scope,上面的代碼會(huì)實(shí)例化兩次Engine類(lèi),因此會(huì)有兩次"Create Engine"輸出。現(xiàn)在我們?cè)谟蠤Scope的情況測(cè)試下勞動(dòng)成果:

public static void main(String[] args) {
    Car car = new Car();

    System.out.println(car.engineA.hashCode());
    System.out.println(car.engineB.hashCode());
}

輸出

Create Engine

bingo!我們確實(shí)通過(guò)@Scope實(shí)現(xiàn)了局部的單例。

Dagger2原理分析

前面啰里啰嗦的介紹了Dagger2的基本使用,接下來(lái)我們?cè)俜治龇治鰧?shí)現(xiàn)原理。這里不會(huì)分析Dagger2根據(jù)注解生成各種代碼的原理,關(guān)于Java注解以后有機(jī)會(huì)再寫(xiě)一篇文章來(lái)介紹。后面主要分析的是Dagger2生成的各種類(lèi)如何幫我們實(shí)現(xiàn)依賴(lài)注入,為了便于理解我這里選了前面相對(duì)簡(jiǎn)單的案例B來(lái)做分析。

Dagger2編譯期生成的代碼位于build/generated/source/apt/debug/your package name/下面:

首先我們看看Dagger2依據(jù)依賴(lài)提供方MarkCarModule生成的對(duì)應(yīng)工廠(chǎng)類(lèi)MarkCarModule_ProvideEngineFactory。為了方便大家理解對(duì)比,后面我一律會(huì)把自己寫(xiě)的類(lèi)和Dagger2生成的類(lèi)一并放出來(lái)。

/**
* 我們自己的類(lèi)
*/
@Module
public class MarkCarModule {

    public MarkCarModule(){ }

    @Provides Engine provideEngine(){
        return new Engine("gear");
    }
}

/**
* Dagger2生成的工廠(chǎng)類(lèi)
*/
public final class MarkCarModule_ProvideEngineFactory implements Factory {
  private final MarkCarModule module;

  public MarkCarModule_ProvideEngineFactory(MarkCarModule module) {
    assert module != null;
    this.module = module;
  }

  @Override
  public Engine get() {
    return Preconditions.checkNotNull(
        module.provideEngine(), "Cannot return null from a non-@Nullable @Provides method");
  }

  public static Factory create(MarkCarModule module) {
    return new MarkCarModule_ProvideEngineFactory(module);
  }

  /** Proxies {@link MarkCarModule#provideEngine()}. */
  public static Engine proxyProvideEngine(MarkCarModule instance) {
    return instance.provideEngine();
  }
}

我們可以看到MarkCarModule_ProvideEngineFactory中的get()調(diào)用了MarkCarModuleprovideEngine()方法來(lái)獲取我們需要的依賴(lài)Engine,MarkCarModule_ProvideEngineFactory的實(shí)例化有crate()創(chuàng)建,并且MarkCarModule的實(shí)例也是通過(guò)create()方法傳進(jìn)來(lái)的。那么這個(gè)create()一定會(huì)在哪里調(diào)用的,我們接著往下看。

前面提到@Component是依賴(lài)提供方(MarkCarModule)和依賴(lài)需求方(Car)之前的橋梁,那我看看Dagger2是如何通過(guò)CarComponent將兩者聯(lián)系起來(lái)的。

/**
* 我們自己的類(lèi)
*/
@Component(modules = {MarkCarModule.class})
public interface CarComponent {

    void inject(Car car);
}

/**
* Dagger2生成的CarComponent實(shí)現(xiàn)類(lèi)
*/
public final class DaggerCarComponent implements CarComponent {
  private Provider provideEngineProvider;

  private MembersInjector carMembersInjector;

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

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

  public static CarComponent create() {
    return builder().build();
  }

  @SuppressWarnings("unchecked")
  private void initialize(final Builder builder) {

    this.provideEngineProvider = MarkCarModule_ProvideEngineFactory.create(builder.markCarModule);

    this.carMembersInjector = Car_MembersInjector.create(provideEngineProvider);
  }

  @Override
  public void inject(Car car) {
    carMembersInjector.injectMembers(car);
  }

  public static final class Builder {
    private MarkCarModule markCarModule;

    private Builder() {}

    public CarComponent build() {
      if (markCarModule == null) {
        this.markCarModule = new MarkCarModule();
      }
      return new DaggerCarComponent(this);
    }

    public Builder markCarModule(MarkCarModule markCarModule) {
      this.markCarModule = Preconditions.checkNotNull(markCarModule);
      return this;
    }
  }
}

通過(guò)上面的代碼我們看到Dagger2依據(jù)CarComponent接口生成了實(shí)現(xiàn)類(lèi)DaggerCarComponent(沒(méi)錯(cuò)這正是我們?cè)贑ar的構(gòu)造函數(shù)中使用DaggerCarComponent)。DaggerCarComponent在build的時(shí)候?qū)嵗?b>DaggerCarComponent對(duì)象,并首先調(diào)用MarkCarModule_ProvideEngineFactory.create(builder.markCarModule)始化了provideEngineProvider變量,接著調(diào)用Car_MembersInjector.create(provideEngineProvider)初始化了carMembersInjector變量。當(dāng)我們手動(dòng)在Car類(lèi)的構(gòu)造函數(shù)中調(diào)用inject(Car car)方法時(shí)會(huì)執(zhí)行carMembersInjector.injectMembers(car)。所以接下來(lái)我們要看看Car_MembersInjector的實(shí)現(xiàn)。

public final class Car_MembersInjector implements MembersInjector {
  private final Provider engineProvider;

  public Car_MembersInjector(Provider engineProvider) {
    assert engineProvider != null;
    this.engineProvider = engineProvider;
  }

  public static MembersInjector create(Provider engineProvider) {
    return new Car_MembersInjector(engineProvider);
  }

  @Override
  public void injectMembers(Car instance) {
    if (instance == null) {
      throw new NullPointerException("Cannot inject members into a null reference");
    }
    instance.engine = engineProvider.get();
  }

  public static void injectEngine(Car instance, Provider engineProvider) {
    instance.engine = engineProvider.get();
  }
}

Car_MembersInjector中的create()用于實(shí)例化自己,這個(gè)方法前面我們看到是在DaggerCarComponent中調(diào)用的。injectMembers(Car instance)engineProvider.get()的返回值賦給了依賴(lài)需求方Car的engine變量,而engineProvider.get()正是本節(jié)一開(kāi)始我們提到的MarkCarModule_ProvideEngineFactory中的get()方法。至此整個(gè)依賴(lài)注入的流程就完成了。更復(fù)雜的應(yīng)用場(chǎng)景會(huì)生成更加復(fù)雜的代碼,但原理都和前面分析的大同小異。

總結(jié)

這篇文章只是通過(guò)一些簡(jiǎn)單的例子介紹了Dagger2的相關(guān)概念及使用,實(shí)際項(xiàng)目中的應(yīng)用遠(yuǎn)比這里的例子要復(fù)雜。關(guān)于Dagger2在實(shí)際項(xiàng)目中的應(yīng)用可以參照這個(gè)開(kāi)源項(xiàng)目 https://github.com/BaronZ88/MinimalistWeather(項(xiàng)目采用MVP架構(gòu),其中View層和Presenter層的解耦就是通過(guò)Dagger2來(lái)實(shí)現(xiàn)的)。

MinimalistWeather是一款開(kāi)源天氣App,開(kāi)發(fā)此項(xiàng)目主要是為展示各種開(kāi)源庫(kù)的使用方式以及Android項(xiàng)目的架構(gòu)方案,并作為團(tuán)隊(duì)開(kāi)發(fā)規(guī)范的一部分。項(xiàng)目中每一個(gè)字母、每一個(gè)命名、每一行代碼都是經(jīng)過(guò)仔細(xì)考究的;但是由于時(shí)間精力有限,項(xiàng)目UI未做嚴(yán)格要求。本著精益求精、提供更好開(kāi)源項(xiàng)目和更美天氣應(yīng)用的原則,因此期望有興趣的開(kāi)發(fā)和UED同學(xué)可以一起來(lái)完成這個(gè)項(xiàng)目。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/66431.html

相關(guān)文章

  • 軟件測(cè)試江湖之公會(huì)武器之爭(zhēng)

    摘要:為了保證各自的核心利益,避免盲目惡性競(jìng)爭(zhēng),最終三大公會(huì)達(dá)成了一個(gè)共識(shí)將軟件測(cè)試江湖里的神兵利器分為四大類(lèi)功能自動(dòng)化測(cè)試武器性能測(cè)試武器測(cè)試管理武器單元測(cè)試武器。 有人的地方就有江湖,有江湖的地方就有恩怨。 軟件測(cè)試也有自己的江湖,也有自己的紛爭(zhēng)。 軟件測(cè)試江湖一直存在于武林中,只是對(duì)外行事低調(diào),從不惹是非,是以未受到武林中各路人士的關(guān)注,直到近年來(lái)互聯(lián)網(wǎng)這股勢(shì)力的崛起將軟件測(cè)試這一傳統(tǒng)...

    Berwin 評(píng)論0 收藏0
  • 軟件測(cè)試江湖之公會(huì)武器之爭(zhēng)

    摘要:為了保證各自的核心利益,避免盲目惡性競(jìng)爭(zhēng),最終三大公會(huì)達(dá)成了一個(gè)共識(shí)將軟件測(cè)試江湖里的神兵利器分為四大類(lèi)功能自動(dòng)化測(cè)試武器性能測(cè)試武器測(cè)試管理武器單元測(cè)試武器。 有人的地方就有江湖,有江湖的地方就有恩怨。 軟件測(cè)試也有自己的江湖,也有自己的紛爭(zhēng)。 軟件測(cè)試江湖一直存在于武林中,只是對(duì)外行事低調(diào),從不惹是非,是以未受到武林中各路人士的關(guān)注,直到近年來(lái)互聯(lián)網(wǎng)這股勢(shì)力的崛起將軟件測(cè)試這一傳統(tǒng)...

    gplane 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<