Dagger2系列:
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(限定符)了
老樣子赊豌,先看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è)成員變量memberA
和memberB
遇到點(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[]里,不然無效