为了介绍Dagger2的使用,我们搭建了一个Demo来逐步分析,大家可以在
这里下载源码(https://github.com/dushaofeng/DaggerDemo.git)。
上一节我们介绍了
《Dagger2教程三之构造方法带参数的情况(原)》这一节我们来讨论如果注入类的构造方法中的参数不同或者注入类包含多个构造方法时的情况处理。
一、包含可变参数的构造方法的情况
这里的"可变参数"指的是
注入类构造方法传递的参数可能每个都不同,比如对于BeanNeedParam的注入类的构造方法:
public BeanNeedParam(String name) {
this.mName = name;
}
我们希望拿到两个BeanNeedParam对象,其中一个对象的mName="AAA",而另一个对象的mName="BBB",那么我们可以这样实现:
1.1、改造BeanModule
在BeanModule中创建两个方法来分别返回不同的BeanNeedParam对象,并使用@Named注释来区分这两个方法:
@Named("TypeA")
@Provides
public BeanNeedParam providerBeanA() {
return new BeanNeedParam("AAA");
}
@Named("TypeB")
@Provides
public BeanNeedParam providerBeanB() {
return new BeanNeedParam("BBB");
}
在这里我们引入了Dagger中的又一个新的注释标记:
@Named,他的作用相当于给方法添加了一个新的属性,来区分当前注入类的不同注入方式。
更通俗的理解是,告诉Dagger,
在BeanModule中存在两种方法来获得BeanNeedParam对象,其中一个叫做TypeA,另一个叫做TypeB,具体使用哪个请按照需求来选择。
1.2、改造Activity中使用方式
既然已经给Dagger准备好了不同的选择,那么接下来只需要告诉Dagger当前需要使用哪个就可以了。
比如对于Activity来说,我们创建当前就需要两个BeanNeedParam对象,那么可以这么定义:
@Named("TypeA")
@Inject
BeanNeedParam mBeanNeedParamAAA;
@Named("TypeB")
@Inject
BeanNeedParam mBeanNeedParamBBB;
这就很明确的告诉Dagger,
请用TypeA的构造方法创建BeanNeedParam并交给mBeanNeedParamAAA使用,用TypeB的构造方法创建BeanNeedParam并交给mBeanNeedParamBBB使用。
下面我们分别获取mBeanNeedParamAAA和mBeanNeedParamBBB中的Named值来验证一下结果:
其结果就是mBeanNeedParamAAA中的mName确是来自于providerBeanA(),而mBeanNeedParamBBB中的mName则来自于providerBeanB()。
二、注入类拥有多个构造方法的情况
其实知道了如何处理多参数的情况,就知道如何来处理多构造方法的情况,我们来看具体如何实现。
我们先在BeanNeedParam的注入类中添加另外一个构造方法,
其需要传入的不再是String,而是一个int型的数据,这样他就拥有了两个构造方法:
// 需要String类型的参数
public BeanNeedParam(String name) {
this.mName = name;
}
// 需要int类型的参数
public BeanNeedParam(int number) {
this.mNumber = number;
}
接下来我们看如何实现该情况下的注入。
2.1、改造BeanModule
我们还是先来改造BeanModule,我们需要提供两个不同的方法来创建不同的BeanNeedParam:
@Named("TypeString")
@Provides
public BeanNeedParam prividerBeanWithString() {
//使用string类型构造方法,并传递"String"的参数
return new BeanNeedParam("String");
}
@Named("TypeInt")
@Provides
public BeanNeedParam prividerBeanWithInt() {
//使用int类型构造方法,传递"2017"的参数
return new BeanNeedParam(2017);
}
这里我们看到其实是和刚才介绍多参数的情况是一样的,
只不过我们用"TypeString"和"TypeInt"来区分不同的构造方法而已。
2.2、改造Activity
同理,我们在Activity中也通过"TypeString"和"TypeInt"的注释来获取不同的BeanNeedParam对象:
//不同构造方法的注入
@Named("TypeString")
@Inject
BeanNeedParam mBeanNeedParamString;
//不同构造方法的注入
@Named("TypeInt")
@Inject
BeanNeedParam mBeanNeedParamInt;
这样一来,mBeanNeedParamString中的mNumber就会使用prividerBeanWithString中传递的"String"值,而mBeanNeedParamInt中的mNumber就会使用prividerBeanWithInt中传递的"2017"的值。
将他们显示出来:
//测试不同构造方法的情况
if (mBeanNeedParamString != null) {
Log.d(TAG, "mBeanNeedParamString Name:" + mBeanNeedParamString.getName() + ",Number:" + mBeanNeedParamString.getNumber());
}
if (mBeanNeedParamInt != null) {
Log.d(TAG, "mBeanNeedParamInt Name:" + mBeanNeedParamInt.getName() + ",Number:" + mBeanNeedParamInt.getNumber());
}
其效果如图所示:
三、更换其他注释符
如果觉得@Named这个标识符有歧义或者使用字符串的形式容易写错,那么可以利用Dagger
自定义一个全新的注释符。下面我们就来创建一个全新的"
SelfType"名称的注释符。
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface SelfType {
int value() default 1;
}
请注意,
这个注释符的类型是int,且默认值为1。
然后我们就可以在BeanModule中如此使用他来区分不同的构造方法:
// 对于SelfType为1的变量,使用"A"作为构造方法参数
@SelfType(1)
@Provides
public BeanNeedParam prividerBeanWithTypeAnnotationA() {
return new BeanNeedParam("A");
}
// 对于SelfType为2的变量,使用"B"作为构造方法参数
@SelfType(2)
@Provides
public BeanNeedParam prividerBeanWithTypeAnnotationB() {
return new BeanNeedParam("B");
}
然后在Activity中使用:
@SelfType(1)
@Inject
BeanNeedParam mBeanNeedParamSelfTypeA;
@SelfType(2)
@Inject
BeanNeedParam mBeanNeedParamSelfTypeB;
这样一来,mBeanNeedParamSelfTypeA对象就会使用BeanNeedParam("A")来创建,而mBeanNeedParamSelfTypeB就会使用BeanNeedParam("B")来创建。
同时,由于我们定义SelfType的时候其默认值就是1,
因此下面两种写法是完全等效的:
//使用默认值:1
@SelfType
@Inject
BeanNeedParam mBeanNeedParamSelfTypeA;
//手动写入当前值:1
@SelfType(1)
@Inject
BeanNeedParam mBeanNeedParamSelfTypeA;
至此,Dagger2中常用(必备)的注释就介绍完了,接下来我们来介绍一些高阶注释的使用:
《Dagger2教程五之单例模式》。