本篇是我写博客的第一篇,基于自己表达能力太差于是就想通过写博客来提高自己,表达可能会相当乱,自己本身水平一般般,如果有啥错误欢迎大家指出,如果能帮到大家那就是我最大的收获。
最近写项目的时候听学长的建议用了下Dagger2这个框架,发现这个框架特别好用,感觉整个项目的逼格就上去了。不过Dagger2在使用上还是有一点难度,当然可能对我这种新手而言,大神分分钟拿来使用。Dagger2也是谷歌官方推荐使用的框架。那么Dagger2是什么:
dagger2是一个基于JSR-330标准的依赖注入框架,在编译期间自动生成代码,负责依赖对象的创建。这句话看起来很官方,没错这是我在其他博客复制粘贴的。简单说就是通过这个框架,你不在用new来创建对象,而是写个注解@Inject就初始化好对象了。所谓的依赖就是:
A a = new A(B b);
我们就可以说b是a的依赖,因为预要创建a,需先创建b。我们想一下平时在Activity上是不是有很多成员变量,这些成员变量都是Activity的依赖,通常我们写一个Init()函数专用来初始化成员变量,如果这些成员变量又依赖于其他变量如像A这种,那我们还得先实例化B类对象。
public class DaggerActivity extends AppCompatActivity {
A a1;
A a2;
A a3;
A a4;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init() {
B b1 = new B();
a1 = new A(b1);
B b2 = new B();
a1 = new A(b2);
B b3 = new B();
a1 = new A(b3);
B b4 = new B();
a1 = new A(b4);
}
}
这就尴尬了一下好多行代码,看着极不舒服。如果使用Dagger2则变成这样子:
public class DaggerActivity extends AppCompatActivity {
@Inject
A a1;
@Inject
A a2;
@Inject
A a3;
@Inject
A a4;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerActivityComponent.create().inject(this);
}
}
搞定。。。是不是很简洁明了
那么首先介绍下Dagger2最重要的几个注解
@Component:用这个注解修饰的叫做注入器,这个注解只能修饰接口和抽象类,通过注入器结合@Inject注解就能完成依赖的注入。如上代码:
@Inject
A a1;
DaggerActivityComponent.create().inject(this);
DaggerActivityComponent这个就是注入器的实现类,通过inject()方法,参数是Activity,为自己的依赖实现注入。注入哪些依赖用@Inject标识,这样就成功地将a1注入。所以@Inject的作用是
- 标记哪些依赖是我们要注入的
- 标记哪些要生成哪些依赖
第二点可以请看A和B类的代码
A类代码
public class A {
private String name;
private int id;
@Inject
public A(B b) {
}
//...省略get,set方法
}
B类代码
public class B {
private String name;
private int id;
@Inject
public B() {
}
//...省略get,set方法
}
A的构造器和B的构造器用@Inject标记,说明可以生成A类的依赖和B类的依赖。这里发现生成A类的对象依赖于B类对象,很明显注入器在注入A类对象的时候,肯定会先生成B类依赖,然后再注入。
看到这里可能大家有个疑问了,DaggerActivityComponent这个东西是怎么生成的,以及他是怎么实现依赖的注入的。我之前说@Component只能修饰接口和抽象类,下面是我写的接口:
@Component
public interface ActivityComponent {
void inject(DaggerActivity daggerActivity);
}
那么DaggerActivityComponent肯定和这个接口有关,实际上DaggerActivityComponent是利用APT注解处理工具动态生成的代码,你会发现你在module添加dependencies会添加一个东西:
apt 'com.google.dagger:dagger-compiler:2.0'
那么DaggerActivityComponent这个类在哪呢,如下图:切换到Project模式
DaggerActivityComponent 代码如下:
@Generated("dagger.internal.codegen.ComponentProcessor")
public final class DaggerActivityComponent implements ActivityComponent {
private Provider<A> aProvider;
private MembersInjector<DaggerActivity> daggerActivityMembersInjector;
private DaggerActivityComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
public static ActivityComponent create() {
return builder().build();
}
private void initialize(final Builder builder) {
this.aProvider = A_Factory.create(B_Factory.create());
this.daggerActivityMembersInjector = DaggerActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), aProvider);
}
@Override
public void inject(DaggerActivity daggerActivity) {
daggerActivityMembersInjector.injectMembers(daggerActivity);
}
public static final class Builder {
private Builder() {
}
public ActivityComponent build() {
return new DaggerActivityComponent(this);
}
}
}
DaggerActivityComponent类有Provider的成员变量,它是个接口,内容提供者,可以通过get()方法获取A的实例对象。
public interface Provider<T> {
T get();
}
DaggerActivityComponent还有个MembersInjector类,这个是成员注入器,也是个接口,上面调用DaggerActivityComponent.inject()方法实际上是调用MembersInjector的inject()方法。
public interface MembersInjector<T> {
void injectMembers(T instance);
}
我们知道依赖的注入是通过DaggerActivityComponent.create().inject(this)开始的,我们来看一下他的流程:
- DaggerActivityComponent里有个Builder对象,可见他是通过建造者模式去构建对象,先create()生成一个Builder,在调用Builder.builder(),最后还是调用了
private DaggerActivityComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
为什么要绕这么一圈呢 心好累,然后调用initialize()
private void initialize(final Builder builder) {
this.aProvider = A_Factory.create(B_Factory.create());
this.daggerActivityMembersInjector = DaggerActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), aProvider);
}
在这个方法中,初始化成员注入器和内容提供者,A_Factory是Factory接口的实现,Factory又继承Provider - - 什么方法都没有,你又在逗我
public interface Factory<T> extends Provider<T> {
}
public final class A_Factory implements Factory<A> {
private final Provider<B> bProvider;
public A_Factory(Provider<B> bProvider) {
assert bProvider != null;
this.bProvider = bProvider;
}
@Override
public A get() {
return new A(bProvider.get());
}
public static Factory<A> create(Provider<B> bProvider) {
return new A_Factory(bProvider);
}
}
调用A_Factory.create()方法完成对A_Factory的创建,注意这里传入了B_Factory,因为B是A的依赖,创建A时候需要用到B,所以A_Factory含有一个B_Factory的成员变量,同时重写Provider的get()方法,return new A(bProvider.get()), B_Factory与此类似只是直接返回B的实例。
因为每一次都返回new 出来的对象,所以一个类中的注入相同的依赖,每个依赖都是新的对象,而不是同一个对象,当然dagger2可以实现单例,这个在下面再说。
然后是成员注入器的生成,第一参数是MembersInjectors.noOp()的返回值,它是一个空实现的MembersInjector,表示注入已经到达父类的最顶端,第二个参数是A类的内容提供者。
this.daggerActivityMembersInjector = DaggerActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), aProvider);
@SuppressWarnings("unchecked")
public static <T> MembersInjector<T> noOp() {
return (MembersInjector<T>) NoOpMembersInjector.INSTANCE;
}
private static enum NoOpMembersInjector implements MembersInjector<Object> {
INSTANCE;
@Override public void injectMembers(Object instance) {
if (instance == null) {
throw new NullPointerException();
}
}
}
最后调用inject(DaggerActivity daggerActivity)方法,实质上是调用daggerActivityMembersInjector.injectMembers(daggerActivity),
它首先判断一下空,然后调用父类的注入器为父类注入依赖,因为这边父类没有@inject标识的依赖,所以父类注入器supertypeInjector就是我们之前传入的空实现的MembersInjectors.noOp()的返回值。然后为DaggerActivity 的成员变量A注入依赖,因为这边是直接通过对象引用a,所以成员变量不能用private修饰。这样就为DaggerActivity的成员变量依赖注入好实例。
//a1AndA2AndA3AndA4Provider是上面传入的Provider<A>
public void injectMembers(DaggerActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
supertypeInjector.injectMembers(instance);
instance.a1 = a1AndA2AndA3AndA4Provider.get();
instance.a2 = a1AndA2AndA3AndA4Provider.get();
instance.a3 = a1AndA2AndA3AndA4Provider.get();
instance.a4 = a1AndA2AndA3AndA4Provider.get();
}
@Inject还可以修饰在方法上面,为方法里的参数注入依赖
@Inject
public void setA(A a){
//a 已经注入依赖 可以对a进行操作
}
对应的实际注入代码
instance.setA(a1AndA2AndA3AndA4AndAProvider.get());
如果我们要注入依赖的类的父类有@Inject标识,比如我们通常会让Activity继承一个BaseActivity,我们在BaseActivity里注入一个B类对象,那么上面注入器的构建就会传入父类的一个注入器,注入时,先注入父类的依赖,再注入子类的依赖。
//DaggerActivityComponent里多了个BaseActivity_MembersInjector成员变量,并在initialize初始化,传入DaggerActivity_MembersInjector。
private void initialize(final Builder builder) {
this.baseActivityMembersInjector = BaseActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), B_Factory.create());
this.aProvider = A_Factory.create(B_Factory.create());
this.daggerActivityMembersInjector = DaggerActivity_MembersInjector.create(baseActivityMembersInjector, aProvider);
}
//注入时,先调用supertypeInjector.injectMembers(instance),supertypeInjector就是传入的BaseActivity_MembersInjector
@Override
public void injectMembers(DaggerActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
supertypeInjector.injectMembers(instance);
instance.a1 = a1AndA2AndA3AndA4AndAProvider.get();
instance.a2 = a1AndA2AndA3AndA4AndAProvider.get();
instance.a3 = a1AndA2AndA3AndA4AndAProvider.get();
instance.a4 = a1AndA2AndA3AndA4AndAProvider.get();
instance.setA(a1AndA2AndA3AndA4AndAProvider.get());
}
通常我们要注入的依赖里还有要注入的依赖,比如A类里面有个B类的成员变量
public class A {
private String name;
private int id;
@Inject
B b1;
@Inject
public A(B b) {
}
//...省略get,set方法
}
这时候DaggerActivityComponent又多了A_MembersInjector,构造传入B_Factory.create(),这个注入器就是用来为A注入B类的依赖。
private void initialize(final Builder builder) {
this.baseActivityMembersInjector = BaseActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), B_Factory.create());
this.aMembersInjector = A_MembersInjector.create(B_Factory.create());
this.aProvider = A_Factory.create(aMembersInjector, B_Factory.create());
this.daggerActivityMembersInjector = DaggerActivity_MembersInjector.create(baseActivityMembersInjector, aProvider);
}
A类注入器传入A的Provider对象里,在A的get()方法里我们还是先生成A类对象,再调用注入器注入,注意 :membersInjector就是我们上面传入的A类注入器,调用injectMembers()方法,为B类依赖注入对象。
@Override
public A get() {
A instance = new A(bProvider.get());
membersInjector.injectMembers(instance);
return instance;
}
@Override
public void injectMembers(A instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.b1 = b1Provider.get();
}
注意:不能循环注入:在A类里面在注入一个A类依赖,这个将会导致一直注入下去,编译会出错。
//不能循环注入
// @Inject
// A a1;
最后简单的总结一下,只要有@Inject标识,就会对应生成相应的MembersInjector,如果要注入的类有父类要注入,先注入父类,在注入子类,最后注意不能循环注入。
- -讲的很罗嗦,大家看看就好,下面几篇依次说下另外几个注解:@Scope,@Module, @Provides, @SubComponent, @Qualifier和@Named。