上一篇介绍了如何简单使用Dagger2,主要介绍了@Inject注解和@Component注解。再来重新理一下使用流程:
- 在MainActivity中使用@Inject注解变量User
- 在User.java的构造器中添加@Inject注解
- 创建类UserComponent并使用@Component注解此类
- 在UserComponent中添加bind(MainActivity activity)方法
- 编译工程,并在MainActivity中使用DaggerUserComponent.builder().build().bind(this);添加依赖注入
虽然实现效果是没有什么问题,但是在完成demo的过程中一直有几个问题困扰着我
- UserComponent中声明的方法为什么叫bind,改用别的名称会有问题吗?
- 假如在User中有多个构造器,并都使用@Inject注解了,那Dagger会使用哪个构造器实例化对象呢?
- 加入User中被@injec注解的构造器含有参数,那Dagger又会怎样实例化对象呢?
- 如果在User中将一个非构造器的方法使用@Inject注解会怎样呢?
问题1, 答案是否定的
在UserComponent中的方法可以取任何名称。我们可以查看编译之后生成的DaggerUserComponent.java中找到答案。
我在UserComponent.java中新加了一个方法aaa(MainActivity activity),如下所示:
@Singleton
public interface UserComponent {
void bind(MainActivity mainActivity);
void aaa(MainActivity mainActivity);
}
然后点击编译,生成DaggerUserComponent类,点进去看一下自动生成的代码如下:
@Override
public void bind(MainActivity mainActivity) {
mainActivityMembersInjector.injectMembers(mainActivity);
}
@Override
public void aaa(MainActivity mainActivity) {
mainActivityMembersInjector.injectMembers(mainActivity);
}
可以看到在DaggerUserComponent中的bind方法和aaa方法都是一样的,所以方法名取什么并不重要
问题2 答案是在一个类中只能有一个被@Inject注解的构造器,否则编译报错
同样在UserComponent中新加一个带String参数的构造器,并使用@Inject注解,重新编译会报如下错误:
问题3 答案是如果Dagger调用一个带参数的构造器(A)时,会继续查找该参数是否有被@Inject注解的构造器(B),如果有就使用该构造器(B)实例化对象,并传递给上一个构造器(A).
新建类Vip.java,如下所示:
public class Vip {
@Inject
public Vip() {
Log.e("DANNY", "Vip default construction called");
}
}
然后修改User.java,创建带Vip参数的构造器,并使用@Inject注解
@Inject
public User(Vip vip) {
Log.e("DANNY", "construction with vip param called");
}
最后编译运行,在Logcat中可以看到如下log
对于问题4 答案很有意思,如果在一个类中除了构造器之外,有其他非构造器也被@Inject注解,那Dagger会在调用完构造器之后,自动调用此方法
比如在User中添加如下修改
@Inject
public User(Vip vip) {
Log.e("DANNY", "construction with vip param called");
}
@Inject
public void init2() {
Log.e("DANNY", "init2 is called");
}
@Inject
public void init() {
Log.e("DANNY", "init is called");
}
可以看到,除了构造器之外,又重新添加了两个被@Inject注解的方法,分别为init2和init。 然后编译并运行工程可以看到如下log
从log中可以看到,虽然init2和init方法并没有在User中主动调用,但是Dagger会找到被@Inject注解的方法 自动调用,并且是按照从上往下的顺序调用