一什么是依赖注入
Dagger2是依赖注入框架。很显然,知道了什么是依赖注入,就知道这个框架是为了解决什么问题而生。
那么什么是依赖注入?
其实很简单,这里我先用代码举个例子,然后我们再说定义:
比如一个人出门,他需要开车,那么先去创建一个Person类,然后再去创建一个Car类代码如下:
public class Person {
private Car car;
public Person() {
car = new Car();
}
public void chumen() {
car.drive();
}
}复制代码
public class Car {
public Car() {
}
public void drive() {
Log.e("rrrrrr", "开汽车出门");
}
}复制代码
人需要借助Car类完成出门这个需求,这种关系我们称为Person类对Car类依赖。
那么什么是注入呢?
有一天,人需要乘坐火车出远门,代码如下:
public class HotCar {
public HotCar() {
}
public void drive() {
Log.e("rrrrrr", "乘火车出远门");
}
}复制代码
public class Person {
// private Car car;
private HotCar hotCar;
public Person() {
// car = new Car();
hotCar= new HotCar();
}
public void chumen() {
// car.drive();
hotCar.drive();
}
}复制代码
人需要借助HotCar类完成出门这个需求,Person类对HotCar依赖。你会发现,每次都要因为选择不同的依赖工具而修改Person类,很繁琐,于是我们想到把需要依赖的对象通过外部传递进来,修改代码如下:
public interface Drivors {
void drive();
}
复制代码
public class Car implements Drivors {
public Car() {
}
@Override
public void drive() {
Log.e("rrrrrr", "开汽车出门");
}
}
复制代码
public class HotCar implements Drivors {
public HotCar() {
}
@Override
public void drive() {
Log.e("rrrrrr", "乘火车出远门");
}
}
复制代码
public class Person {
private Drivors drivors;
public Person(Drivors drivors) {
this.drivors = drivors;
}
public void chumen() {
drivors.drive();
}
}复制代码
使用上边代码:
HotCar hotCar = new HotCar();
Person person = new Person(hotCar);
person.chumen();复制代码
你会发现不管换用什么工具出门,我们不需要再修改Person类中的代码,Person所依赖的对象由外部传入,这种效果我们叫依赖注入。
依赖注入的定义:内部不实例化依赖的对象,由外部传入的写法叫做依赖注入。
我们在日常开发中依赖注入的写法有那些呢?
1通过构造方法注入(传递)
class A {
B b;
C c;
public A(B b, C c) {
this.b = b;
this.c = c;
}
}复制代码
2通过setter方法注入(传递)
class A {
B b;
C c;
public void setB(B b) {
this.b = b;
}
public void setC(C c) {
this.c = c;
}
}复制代码
通过上边的简单代码,我们直到了什么是依赖注入,也知道了依赖注入的方式。
二Component 和Inject去注入对象
我们继续回到开始:Dagger2是依赖注入。我们似乎明白了Dagger2干的事情:就是把需求类内对象赋值的过程。
到此我们了解的Dagger2是为了解决什么问题而诞生的。为依赖注入而诞生
接下来我们一步步去了解怎么通过配置注解,然后完成最简单的依赖注入。
首先我们要添加Dagger2依赖如下:
implementation 'com.google.dagger:dagger:2.7'
annotationProcessor 'com.google.dagger:dagger-compiler:2.7'复制代码
然后我们去创建一个Car类
public class Car {
@Inject
public Car() {
}
public void drive() {
Log.e("rrrrrr", "开汽车出门");
}
}复制代码
然后给构造方法上添加一个@Inject注解,
对应的OneActivity代码如下:
public class OneActivity extends AppCompatActivity {
@Inject
Car car;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_one);
car.drive();
}
}复制代码
使用@Inject去注解这个需要注入的成员变量,下边使用这个对象。运行发现他会报空指针异常。
这个时候我们要去创建一个接口把他们关联起来,代码如下:
@Component
public interface A01Component {
void inject(OneActivity activity);
}复制代码
使用@Component 注解一个接口,接口中定义一个传入需要注入类的对象。然后再需要注入的类中写下如下代码:
DaggerA01Component.builder().build().inject(this);复制代码
继续运行,发现不报错,并且可以调用drive方法,说明我们把对象注入成功。
上边对应的Car构造方法没有参数,但是如果Car有参数,我们怎么才能注入呢?
这个时候我们就需要去创建一个model类对Dagger2提供这个参数。代码如下:
public class Car {
private String name;
@Inject
public Car(String name) {
this.name = name;
}
public void drive() {
Log.e("rrrrrr", name+"开汽车出门");
}
}复制代码
@Module
public class A01Module {
private String name;
public A01Module(String name) {
this.name = name;
}
@Provides
public String provideName() {
return name;
}
}复制代码
然后把Module类和Component类进行关联,如下:
@Component(modules = A01Module.class)
public interface A01Component {
void inject(OneActivity activity);
}复制代码
最后使用如下:
public class OneActivity extends AppCompatActivity {
@Inject
Car car;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_one);
DaggerA01Component.builder().a01Module(new A01Module("李四")).build().inject(this);
car.drive();
}
}复制代码
就完成有参数的类的注入。
三查看Dagger2生成的源码
上边我们通过一个接口就实现了赋值,既然是接口,就一定有实现类,关于实现类的生成涉及到另外一个技术APT技术(通过反射解析注解,生成代码的过程就叫做APT技术)。这里我们不去研究怎么生成的代码,而是去查看源码里边的逻辑。
那么源码怎么找呢?
Project视图下--build--source--apt--包名下就是Dagger2生成的代码:有一下三个文件:
public enum Car_Factory implements Factory<Car> {
INSTANCE;
@Override
public Car get() {
return new Car();
}
public static Factory<Car> create() {
return INSTANCE;
}
}复制代码
public final class DaggerA01Component implements A01Component {
private MembersInjector<OneActivity> oneActivityMembersInjector;
private DaggerA01Component(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
public static A01Component create() {
return builder().build();
}
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.oneActivityMembersInjector = OneActivity_MembersInjector.create(Car_Factory.create());
}
@Override
public void inject(OneActivity activity) {
oneActivityMembersInjector.injectMembers(activity);
}
public static final class Builder {
private Builder() {}
public A01Component build() {
return new DaggerA01Component(this);
}
}
}复制代码
public final class OneActivity_MembersInjector implements MembersInjector<OneActivity> {
private final Provider<Car> carProvider;
public OneActivity_MembersInjector(Provider<Car> carProvider) {
assert carProvider != null;
this.carProvider = carProvider;
}
public static MembersInjector<OneActivity> create(Provider<Car> carProvider) {
return new OneActivity_MembersInjector(carProvider);
}
@Override
public void injectMembers(OneActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.car = carProvider.get();
}
public static void injectCar(OneActivity instance, Provider<Car> carProvider) {
instance.car = carProvider.get();
}
}复制代码
通过上边源码可以看出,把创建的Car对象和传入的OneActivity对象一起传入OneActivity_MembersInjector类中,然后在injectMembers方法中完成的赋值。
上边是一个通过Dagger2实现依赖注入的最简单例子。
四第三方库怎么用Dagger2注入
通过上边的两个例子我们发现,@Component 和 @Inject 的配合就能够使用 Dagger2 了,但这里面存在一个局限,@Inject 只能标记在我们自己编写的类的构造方法中,如果我们使用第三方的库或者标准库的话,我们就没有办法用这两个注解完成依赖注入了,这时候,我们就需要新的注解@Provides 和 @Module
接下来的需求大概是这样,我们假如Person类是第三方库中的类,不让Person类中出现任何注解,然后使用Dagger去注入
public class Pseson {
public Pseson() {
}
public String getName() {
return "张三";
}
}复制代码
然后创建Component
@Component
public interface A02Component {
void inject(TwoActivity activity);
}复制代码
最后使用:
public class TwoActivity extends AppCompatActivity {
@Inject
Pseson person;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_one);
DaggerA02Component.builder().build().inject(this);
person.getName();
}
}复制代码
这个时候编译发现失败,是因为Person构造没有添加注解。这个时候我们就需要去创建一个Model类
@Module
public class A02Module {
@Provides
public Pseson providePerson() {
return new Pseson();
}
}复制代码
值得注意的地方有
- @Provides 修饰的方法一般用 provide 作用方法名前缀。
- @Module 修饰的类一般用 Module 作为后缀。
在 @component 注解后面的括号中取值module.class。
@Component(modules = A02Module.class)
public interface A02Component {
void inject(TwoActivity activity);
}复制代码
这样我们就通过这个四个注解完成了第三方类的对象注入。
如果第三方库中构造方法也有参数,这个我们怎么注入呢?假如上边的Person依赖Car类。
我们就需要修改我们module中的代码,也去提供这个参数即可。修改后的module如下:
@Module
public class A02Module {
@Provides
public Pseson providePerson(Car car) {
return new Pseson(car);
}
@Provides
public Car provideCar() {
return new Car("");
}
}复制代码
这样就完成了第三方库构造方法有参数的注入
五 两种注入方式,那么他们有没有优先级呢?
当然是有的!他们的顺序如下:
代码下载地址:github.com/XiFanYin/Da…