上一期主要介紹了在有一個參數(shù)的情況下Dagger如何運作。這一期將引入另一個int參數(shù)b
那么問題來了,上一期我們提到,@Provides
只認(rèn)類型,不認(rèn)名字,當(dāng)有多個同類型存在時,Dagger如何分辨呢?
事實上,Dagger需要你來標(biāo)注告訴它。這就涉及到@Qualifier
標(biāo)注。Qualifier的含義正是限定詞,而Dagger也提供了自帶的@Named
的Qualifier來應(yīng)對這種情況。
具體用法,就是幫助Dagger解決同類型造成的混淆,可能會出現(xiàn)在構(gòu)造器里面,也可能出現(xiàn)在@Inject
兩個同類型對象時。我們這里暫時還只是用來去除構(gòu)造器里面同類型參數(shù)的問題。
主體代碼
現(xiàn)在ClassA
看起來是這樣:
public class ClassA {
private int a;
private int b;
@Inject
public ClassA(@Named("a") int a, @Named("b") int b) {
this.a = a;
this.b = b;
}
public int getA() {
return a;
}
public int getB() {
return b;
}
}
然后新的ModuleA
:
@Module
public class ModuleA {
private int a;
private int b;
public ModuleA(int a, int b) {
this.a = a;
this.b = b;
}
@Provides
@Named("a")
int provideIntA() {
return a;
}
@Provides
@Named("b")
int provideIntB() {
return b;
}
}
然后ClassAComponent
沒有任何變化。
看看MainActivity
:
public class MainActivity extends AppCompatActivity {
@Inject ClassA classA;
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerClassAComponent.builder()
.moduleA(new ModuleA(2, 3))
.build().inject(this);
Log.d(TAG, classA.getA() + ":" + classA.getB());
}
}
運行可以看出打印了"2:3"。如果我們調(diào)換ModuleA
里兩個@Named
標(biāo)注,或者調(diào)換ClassA
里面的@Named
標(biāo)注,可以發(fā)現(xiàn)打印為"3:2",這說明確實是ModuleA
按照標(biāo)注來給ClassA
提供對應(yīng)參數(shù)的。
生成代碼
1.ClassA_Factory
public final class ClassA_Factory implements Factory<ClassA> {
private final Provider<Integer> aProvider;
private final Provider<Integer> bProvider;
public ClassA_Factory(Provider<Integer> aProvider, Provider<Integer> bProvider) {
assert aProvider != null;
this.aProvider = aProvider;
assert bProvider != null;
this.bProvider = bProvider;
}
@Override
public ClassA get() {
return new ClassA(aProvider.get(), bProvider.get());
}
public static Factory<ClassA> create(Provider<Integer> aProvider, Provider<Integer> bProvider) {
return new ClassA_Factory(aProvider, bProvider);
}
}
現(xiàn)在ClassA
有了兩個參數(shù),對應(yīng)的就有兩個Provider
。
2.ModuleA_ProvideIntAFactory
與ModuleA_ProvideIntBFactory
和上一期的一脈相承,還是很直白的把ModuleA
里面獲取參數(shù)的方法封裝成為一個工廠:
public final class ModuleA_ProvideIntAFactory implements Factory<Integer> {
private final ModuleA module;
public ModuleA_ProvideIntAFactory(ModuleA module) {
assert module != null;
this.module = module;
}
@Override
public Integer get() {
return Preconditions.checkNotNull(
module.provideIntA(), "Cannot return null from a non-@Nullable @Provides method");
}
public static Factory<Integer> create(ModuleA module) {
return new ModuleA_ProvideIntAFactory(module);
}
/** Proxies {@link ModuleA#provideIntA()}. */
public static int proxyProvideIntA(ModuleA instance) {
return instance.provideIntA();
}
}
public final class ModuleA_ProvideIntBFactory implements Factory<Integer> {
private final ModuleA module;
public ModuleA_ProvideIntBFactory(ModuleA module) {
assert module != null;
this.module = module;
}
@Override
public Integer get() {
return Preconditions.checkNotNull(
module.provideIntB(), "Cannot return null from a non-@Nullable @Provides method");
}
public static Factory<Integer> create(ModuleA module) {
return new ModuleA_ProvideIntBFactory(module);
}
/** Proxies {@link ModuleA#provideIntB()}. */
public static int proxyProvideIntB(ModuleA instance) {
return instance.provideIntB();
}
}
3. MainActivity_MembersInjector
無變化
4. DaggerClassAComponent
public final class DaggerClassAComponent implements ClassAComponent {
private Provider<Integer> provideIntAProvider;
private Provider<Integer> provideIntBProvider;
private Provider<ClassA> classAProvider;
private MembersInjector<MainActivity> mainActivityMembersInjector;
private DaggerClassAComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.provideIntAProvider = ModuleA_ProvideIntAFactory.create(builder.moduleA);
this.provideIntBProvider = ModuleA_ProvideIntBFactory.create(builder.moduleA);
this.classAProvider = ClassA_Factory.create(provideIntAProvider, provideIntBProvider);
this.mainActivityMembersInjector = MainActivity_MembersInjector.create(classAProvider);
}
@Override
public void inject(MainActivity activity) {
mainActivityMembersInjector.injectMembers(activity);
}
public static final class Builder {
private ModuleA moduleA;
private Builder() {}
public ClassAComponent build() {
if (moduleA == null) {
throw new IllegalStateException(ModuleA.class.getCanonicalName() + " must be set");
}
return new DaggerClassAComponent(this);
}
public Builder moduleA(ModuleA moduleA) {
this.moduleA = Preconditions.checkNotNull(moduleA);
return this;
}
}
}
該文件的作用還是把一切整合起來。關(guān)鍵就是順序問題,@Named
標(biāo)注讓initialize
方法知道要用什么順序來構(gòu)造。
到目前為止,ClassA
是我們可以隨意更改的,但現(xiàn)實開發(fā)中很多時候我們并不能做到,比如其來自第三方庫。也就是說我們無法對其構(gòu)造器添加@Inject
或@Named
標(biāo)注,那又怎么辦呢?下期就會解決這個問題。