Dagger2解析5-Qualifier

Dagger2系列:

  1. Dagger2解析-1
  2. Dagger2解析2-Component的依賴關(guān)系
  3. Dagger2解析3-SubComponent
    4.Dagger2解析4-Scope

Dagger版本:2.11

在第二篇Dagger2解析2-Component的依賴關(guān)系中曾經(jīng)提到過枚赡,一個(gè)組件中依賴關(guān)系中不能有相同類型的提供者(構(gòu)造函數(shù)標(biāo)注@Inject的可創(chuàng)建實(shí)例的對(duì)象或者module里標(biāo)注@Provides的方法)西篓,否則會(huì)出現(xiàn)依賴迷失的錯(cuò)誤谤狡,而編譯時(shí)判斷的依據(jù)就是類型是否重復(fù)唧席,可是有些時(shí)候就是會(huì)出現(xiàn)類型相同的不同實(shí)例時(shí)又該如何解決呢瑞你,這里就需要用到本篇的主角Qualifier(限定符)了

通過限定符,可以從多個(gè)提供相同類型的Provider中找出正確的那個(gè)

老樣子赊豌,先看Qualifier類

package javax.inject;
// ......
/**
 *Identifies qualifier annotations. Anyone can define a new qualifier. A
 * qualifier annotation:
 * ......
 */
@Target(ANNOTATION_TYPE)
@Retention(RUNTIME)
@Documented
public @interface Qualifier {}

Qualifier同樣是javax.inject包下的一個(gè)注解類吝秕,和Scope類似,也是能夠自定義的

1.示例

代碼擼起备蚓,還是老朋友Target和Member课蔬,這次Module會(huì)有多個(gè)提供Member的方法

class Member(val name: String)

class Target {

    @field:[Inject CustomQualifier(name = "A")]
    lateinit var memberA: Member

    @field:[Inject CustomQualifier(name = "B")]
    lateinit var memberB: Member
}

@Module
class MemberModule {
    @CustomQualifier(name = "A")
    @Provides
    fun provideMemberA(): Member = Member("by provideMemberA")

    @CustomQualifier(name = "B")
    @Provides
    fun provideMemberB(): Member = Member("by provideMemberB")
}

@Component(modules = arrayOf(MemberModule::class))
interface TargetComponent {
    fun inject(target: Target)
}

ps:用java的無視就好,關(guān)于Target中的兩個(gè)成員變量memberAmemberB遇到點(diǎn)小坑郊尝,之前直接這么寫的

    @Inject 
    @CustomQualifier(name = "A")]
    lateinit var memberA: Member

    @Inject 
    @CustomQualifier(name = "B")]
    lateinit var memberB: Member

一直編譯不通過二跋,提示找不到能提供實(shí)例的provider,后來在stackoverflow上找到一篇解答流昏,才發(fā)現(xiàn)kotlin里屬性的標(biāo)注要用@field:[/* 和成員變量相關(guān)的注解放在這 */]

2. 代碼分析

由于例子簡(jiǎn)單扎即,和 Dagger2解析-1的相比也不過就多了一個(gè)工廠,事實(shí)上况凉,這兩個(gè)工廠的代碼也是幾乎一樣的谚鄙,唯一不同的是get方法調(diào)用的module對(duì)應(yīng)的兩個(gè)provide方法

public final class MemberModule_ProvideMemberAFactory implements Factory<Member> {
  //...
  @Override
  public Member get() {
    return Preconditions.checkNotNull(
        // 調(diào)用的是module的provideMemberA
        module.provideMemberA(), "Cannot return null from a non-@Nullable @Provides method");
  }
  //...
}

public final class MemberModule_ProvideMemberBFactory implements Factory<Member> {
  // ...
  @Override
  public Member get() {
    return Preconditions.checkNotNull(
        // 調(diào)用的是module的provideMemberB
        module.provideMemberB(), "Cannot return null from a non-@Nullable @Provides method");
  }
  // ...
}

然后是Injector

public final class Target_MembersInjector implements MembersInjector<Target> {
  private final Provider<Member> memberAProvider;
  private final Provider<Member> memberBProvider;
  //...
  @Override
  public void injectMembers(Target instance) {
    if (instance == null) {
      throw new NullPointerException("Cannot inject members into a null reference");
    }
    // complier生成代碼時(shí)通過限定符注解成功找到了對(duì)應(yīng)的提供依賴的provider
    instance.memberA = memberAProvider.get();
    instance.memberB = memberBProvider.get();
  }
}

可以看到,代碼上并沒有什么奇怪的操作茎刚,所以說明這個(gè)注解提供給編譯器生成代碼后就沒啥用了襟锐,其他的也沒啥好說的了撤逢,通過對(duì)module和需要被注入的依賴上標(biāo)注限定符膛锭,編譯器在發(fā)現(xiàn)重復(fù)的Provider時(shí),就能通過限定符去尋找正確的Provider了

ps1:關(guān)于注解不太明白蚊荣,retention保留的問題初狰,照實(shí)現(xiàn)原理看,這些注解互例,包括@Component @Module @Scope以及本篇的@Qualifier都應(yīng)該不需要在運(yùn)行期保留啊奢入,但寫法都是@Retention(RetentionPolicy.RUNTIME)?望大佬指明
ps2:關(guān)于kotlin的注解類annotation class媳叨,它的Retention默認(rèn)就是RUNTIME腥光,所以可以不寫关顷,例如本篇中的CustomQualifier可以寫成

@Qualifier
annotation class CustomQualifier(val name: String = "")

3.總結(jié)

1.這個(gè)注解是用來解決依賴迷失的,適合注入對(duì)象需要多個(gè)同類型依賴的場(chǎng)合武福,視情況個(gè)人覺得Scope也能拿來解決這個(gè)問題
2.和前面的注解不同议双,kotlin上用要注意把相關(guān)注解寫在@field[]里,不然無效

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末捉片,一起剝皮案震驚了整個(gè)濱河市平痰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌伍纫,老刑警劉巖宗雇,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異莹规,居然都是意外死亡赔蒲,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門良漱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嘹履,“玉大人,你說我怎么就攤上這事债热±担” “怎么了?”我有些...
    開封第一講書人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵窒篱,是天一觀的道長(zhǎng)焕刮。 經(jīng)常有香客問我,道長(zhǎng)墙杯,這世上最難降的妖魔是什么配并? 我笑而不...
    開封第一講書人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮高镐,結(jié)果婚禮上溉旋,老公的妹妹穿的比我還像新娘。我一直安慰自己嫉髓,他們只是感情好观腊,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著算行,像睡著了一般梧油。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上州邢,一...
    開封第一講書人閱讀 49,829評(píng)論 1 290
  • 那天儡陨,我揣著相機(jī)與錄音,去河邊找鬼。 笑死骗村,一個(gè)胖子當(dāng)著我的面吹牛嫌褪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播胚股,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼渔扎,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了信轿?” 一聲冷哼從身側(cè)響起晃痴,我...
    開封第一講書人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎财忽,沒想到半個(gè)月后倘核,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡即彪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年紧唱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片隶校。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡漏益,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出深胳,到底是詐尸還是另有隱情绰疤,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布舞终,位于F島的核電站轻庆,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏敛劝。R本人自食惡果不足惜余爆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望夸盟。 院中可真熱鬧蛾方,春花似錦、人聲如沸上陕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽唆垃。三九已至五芝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間辕万,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留渐尿,地道東北人醉途。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像砖茸,于是被迫代替她去往敵國(guó)和親隘擎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

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