走馬觀花-Dagger2 - @Inject 和 @Component

@Inject

  • @Inject 使用在一個類的屬性上枕荞,表示該類需要一個依賴
  • @Inject 使用在一個類的構(gòu)造方法上柜候,表示由該構(gòu)造方法提供依賴

假設有個路人Passerby,需要一輛車Car躏精,則可以表示為 Passerby 依賴于 Car渣刷。代碼表示:

Passerby :

public class Passerby {
    public Car mCar;
    public Passerby(Car car) {
        mCar = car;
        System.out.println("I'm a Passerby!");
    }
}

Car :

public class Car {
    @Inject
    public Car() {
        System.out.println("I'm a Car!");
    }
}

當且僅當在 Car 的構(gòu)造器上使用 @Inject 時,編譯矗烛,在 \build\generated\source\apt\debug\com\oliver\test 目錄下自動生成了 Car_Factory.java 文件:

public final class Car_Factory implements Factory<Car> {
  private static final Car_Factory INSTANCE = new Car_Factory();

  @Override
  public Car get() {
    return provideInstance();
  }

  public static Car provideInstance() {
    return new Car();
  }

  public static Car_Factory create() {
    return INSTANCE;
  }

  public static Car newCar() {
    return new Car();
  }
}

Car_Factory 實現(xiàn)了 Factory<T> 接口飞主, Factory<T> 繼承至 Provider<T> 接口:

public interface Factory<T> extends Provider<T> {
}

public interface Provider<T> {
    /**
     *  返回注入的實例
     */
    T get();
}

觀察 Car_Factory.java ,可以知道:

  • 構(gòu)造器使用了 @Inject 注解高诺,就會生成 類名_FactoryFactory<T> 實現(xiàn)類碌识。
  • get() 確實返回我們注入的實例
  • 自動生成兩個返回 new Car() 的方法,分別是 newCar()provideInstance()

Passerby 的依賴標注 @Inject 注解虱而,再次編譯:

 @Inject
 public Car mCar;

\build\generated\source\apt\debug\com\oliver\test 目錄下多了一個 Passerby_MembersInjector 的類:

public final class Passerby_MembersInjector implements MembersInjector<Passerby> {
  private final Provider<Car> mCarProvider;

  public Passerby_MembersInjector(Provider<Car> mCarProvider) {
    this.mCarProvider = mCarProvider;
  }

  public static MembersInjector<Passerby> create(Provider<Car> mCarProvider) {
    return new Passerby_MembersInjector(mCarProvider);
  }

  @Override
  public void injectMembers(Passerby instance) {
    injectMCar(instance, mCarProvider.get());
  }

  public static void injectMCar(Passerby instance, Car mCar) {
    instance.mCar = mCar;
  }
}

該類實現(xiàn)了 MembersInjector<T> 接口:

public interface MembersInjector<T> {
  void injectMembers(T instance);
}

注意 Passerby_MembersInjector 的方法 injectMembers(T instance),其參數(shù)是 Passerby 類型筏餐,也就是說,該方法的使命就是給其參數(shù)持有的成員變量賦值牡拇,然后外界想辦法獲得這個參數(shù)就行了魁瞪,參數(shù)依賴的對象已經(jīng)在此處完成了注入的過程。

 @Override
  public void injectMembers(Passerby instance) {
    injectMCar(instance, mCarProvider.get());
  }

  public static void injectMCar(Passerby instance, Car mCar) {
    instance.mCar = mCar;
  }

另外惠呼, Passerby_MembersInjector 多出了一個成員 Provider<Car>导俘,即一個類的成員變量標注有 @Inject 注解,那么這個成員就會在生成類中生成相應的 Provider<T> 成員剔蹋。根據(jù)上面對 Car_Factory 的分析旅薄,大膽猜測,其實這里的 Provider<Car> 就是生成的 Car_Factory 泣崩。所需依賴也正好在此處注入少梁,即:

instance.mCar =  mCarProvider.get();
mCar = new Car();


///////////////////////////// Car_Factory /////////////////////////////
@Override
public Car get() {
    return provideInstance();
}

public static Car provideInstance() {
    return new Car();
}

上面說到,我們猜測 Provider<Car> 就是生成的 Car_Factory 矫付。那 Provider<Car> 是怎樣賦值的呢凯沪?

public Passerby_MembersInjector(Provider<Car> mCarProvider) {
    this.mCarProvider = mCarProvider;
  }

  public static MembersInjector<Passerby> create(
      Provider<Car> mCarProvider) {
    return new Passerby_MembersInjector(mCarProvider);
  }

可以看到,主要是通過 Passerby_MembersInjector.create()new Passerby_MembersInjector()賦值买优,其中 create() 又是直接調(diào)用構(gòu)造方法的妨马。那這兩個方法是調(diào)用了哪一個?誰調(diào)用的杀赢?這就要說到另外一個注解了: @Component烘跺。

Dagger 的主要功能時依賴注入,從而達到解耦的目的葵陵。所以不會在Xxx_MembersInjector 中直接賦值液荸,這樣的話和 mCar = new Car() 沒什么區(qū)別?所以我猜測脱篙,引入了 @Component 是為了達到依賴方和被依賴方不直接耦合的目的娇钱。但是伤柄,這樣就造成了依賴方和被依賴方都與 @Component 耦合了。所以其實我也不太清楚 @Component 的具體作用文搂。

2019-02-12
@Component 限定了提供依賴的 Module 類适刀,如果有過多個 Module 都提供該依賴,@Componentmodules 字段就指定了到底是哪個具體 Module 來完成這個依賴的提供煤蹭。

@Component

@Inject 使用在成員上表示需要依賴對象笔喉,使用在構(gòu)造器上表示提供自身對象。兩者之間需要 @Component 注解作為依賴關系形成的橋梁硝皂。

@Component 使用在接口或抽象類上常挚,編譯后在 \build\generated\source\apt\debug\com\oliver\test 目錄下生成一個名稱為 Dagger + 被注解的類名稱 的類。例如:

@Component
public interface Ofo {}

生成類名稱: DaggerOfo

@Component 必須包含至少一個abstract component method稽物,以下簡稱 CM奄毡,CM 可以隨意命名,但是必須有滿足 Provider 或者 MembesInjector 約束的簽名贝或。

Provider Method :

Provider Method吼过,以下簡稱 PM ,沒有參數(shù)但是有返回值咪奖。返回一個 {@link Inject injected}{@link Provides provided} 類型盗忱,方法還可以被 @Qualifier 注解標注。也就是說羊赵,返回值必須是 被注入類型被提供類型趟佃。

  • 被注入類型 表示其構(gòu)造器被 @Inject 標注
  • 被提供類型 表示 @Component 包含的 @Module 中被 @Providers 注解標注的方法的返回值類型

注解 @Module@Providers 是什么?下面會說到慷垮。

MembersInjector Method :

MembersInjector Method ,以下簡稱 MM揖闸,MM 有一個參數(shù),并將依賴項注入每個 {@link Inject} 注解的字段和傳遞實例的方法料身,MM 返回 void, 為方便鏈式調(diào)用,也可返回 參數(shù)類型衩茸,芹血。也就是說,參數(shù)類中有成員變量被 @Inject 標注楞慈,且該成員變量類的構(gòu)造器也被 @Inject 標注幔烛。這樣的話,當 @Compment 實現(xiàn)類【DaggerOfo】重寫該方法【void inject(MainActivity activity)】時囊蓝,就會通過成員變量相應生成的【Passerby_Factory】構(gòu)造【Passerby】實例饿悬,賦值給參數(shù)【MainActivity】的成員變量【mPasserby】。具體如下:

public class Passerby {
    @Inject
    public Car mCar;

    public Passerby(){}

    @Inject
    public Passerby(Car car) {
        mCar = car;
        System.out.println("I'm a Passerby!");
    }
    public void go(){
        mCar.go();
    }
}

MainActivity 中使用:

public class MainActivity extends AppCompatActivity {

    @Inject
    Passerby mPasserby;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 注意聚霜,此處注入的參數(shù)this不能為null狡恬,
        DaggerOfo.builder().build().inject(this);
        mPasserby.go();
    }
}

開始使用 @Component 注解:

@Component
public interface Ofo {
    
//    Passerby getPasserby();
    
    // 使用 MembersInjector Method
    void inject(MainActivity activity);
}

在標注了 @Component 注解的類中使用 MM珠叔,生成類如下:

public final class DaggerOfo implements Ofo {
  private DaggerOfo(Builder builder) {}

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

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

  private Passerby getPasserby() {
    return injectPasserby(Passerby_Factory.newPasserby(new Car()));
  }

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

  private Passerby injectPasserby(Passerby instance) {
    Passerby_MembersInjector.injectMCar(instance, new Car());
    return instance;
  }

  private MainActivity injectMainActivity(MainActivity instance) {
    MainActivity_MembersInjector.injectMPasserby(instance, getPasserby());
    return instance;
  }

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

    public Ofo build() {
      return new DaggerOfo(this);
    }
  }
}

可以看到,當我們調(diào)用 inject() 時弟劲,會調(diào)用到 Passerby_MembersInjector#injectMCar():

public static void injectMCar(Passerby instance, Car mCar) {
    // 直接賦值祷安,假設傳進來的 instance == null,報空指針就在所難免了
    instance.mCar = mCar;
}

調(diào)用 injectMainActivity(MainActivity) 之后兔乞,在層層調(diào)用汇鞭,就達到了給成員變量 mPasserbyPasserby 的成員變量 mCar 的注入。

現(xiàn)在在 @Component 注解的類中使用 MP:

@Component
public interface Ofo {

    Passerby getPasserby();

//    void inject(Passerby passerby);
}

生成類 DaggerOfo 如下:

public final class DaggerOfo implements Ofo {
    private DaggerOfo(Builder builder) {}

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

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

    @Override
    public Passerby getPasserby() {
        return injectPasserby(Passerby_Factory.newPasserby(new Car()));
    }

    private Passerby injectPasserby(Passerby instance) {
        Passerby_MembersInjector.injectMCar(instance, new Car());
        return instance;
    }

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

        public Ofo build() {
            return new DaggerOfo(this);
        }
    }
}

可以看到庸追,調(diào)用 getPasserby() 時會自動生成一個 Passerby 實例霍骄,然后給其注入依賴。外界可通過返回值獲取到該實例淡溯。

總結(jié)

  • @Inject 使用在一個類的屬性上腕巡,表示該類需要一個依賴;使用在一個類的構(gòu)造方法上血筑,表示由該構(gòu)造方法提供依賴
  • @Component 注解作為依賴關系形成的橋梁绘沉,至少包含一個 CM。編譯之后會生成 DaggerXxx
  • CM類型是 MM 豺总,在類【假設為A】中使用 DaggerXxx 车伞,則 A 中必須有 @Inject 注解標注的成員變量,用于賦值喻喳。因為經(jīng)過上面生成的 DaggerOfo 來說另玖,在 injectXxx() 中都是這樣模板代碼:instance.mXxx = Xxx_Factory.newXxx(),即賦值操作表伦。
  • CM類型是 PM , 在類【假設為A】中使用 DaggerXxx 來獲取需要注入的對象谦去,然后在使用;例如:
Passerby mPasserby = DaggerOfo.builder().build().getPasserby();
mPasserby.go();
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蹦哼,一起剝皮案震驚了整個濱河市鳄哭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌纲熏,老刑警劉巖妆丘,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異局劲,居然都是意外死亡勺拣,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進店門鱼填,熙熙樓的掌柜王于貴愁眉苦臉地迎上來药有,“玉大人,你說我怎么就攤上這事苹丸》叨瑁” “怎么了苇经?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長羊苟。 經(jīng)常有香客問我塑陵,道長,這世上最難降的妖魔是什么蜡励? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任令花,我火速辦了婚禮,結(jié)果婚禮上凉倚,老公的妹妹穿的比我還像新娘兼都。我一直安慰自己,他們只是感情好稽寒,可當我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布扮碧。 她就那樣靜靜地躺著,像睡著了一般杏糙。 火紅的嫁衣襯著肌膚如雪慎王。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天宏侍,我揣著相機與錄音赖淤,去河邊找鬼。 笑死谅河,一個胖子當著我的面吹牛咱旱,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播绷耍,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼吐限,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了褂始?” 一聲冷哼從身側(cè)響起诸典,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎病袄,沒想到半個月后搂赋,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡益缠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了基公。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片幅慌。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖轰豆,靈堂內(nèi)的尸體忽然破棺而出胰伍,到底是詐尸還是另有隱情齿诞,我是刑警寧澤,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布骂租,位于F島的核電站祷杈,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏渗饮。R本人自食惡果不足惜但汞,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望互站。 院中可真熱鬧私蕾,春花似錦、人聲如沸胡桃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽翠胰。三九已至容贝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間之景,已是汗流浹背斤富。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留闺兢,地道東北人茂缚。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像屋谭,于是被迫代替她去往敵國和親脚囊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,060評論 2 355

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