1. 什么是依赖注入

Dagger 2是Android中比较热门的依赖注入框架,什么是依赖注入呢? 维基百科上是这样描述的:

控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中.

通俗的来讲呢,就是一个类中需要依赖其他对象时,不需要你亲自为那些需要依赖的对象赋值,为那些对象赋值的操作交给了IOC框架.

eg:当我们在一个类的构造函数中通过参数引入另一个类的对象,或者通过set方法设置一个类的对象其实就是使用的依赖注入

//简单的依赖注入,构造方法或者set()方法都属于依赖注入
public class ClassA {
ClassB classB;
public void ClassA(ClassB b) {
classB = b;
}
}

​Dragger2​​​ 使用方式,在 ​​module​​​ 的 ​​build.gradle​​ 中添加如下代码:


android {
...
//添加如下配置
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

annotationProcessor 'com.google.dagger:dagger-compiler:2.22.1'
// if you use the support libraries
implementation 'com.google.dagger:dagger-android-support:2.22.1'
implementation 'com.google.dagger:dagger:2.22.1'

2. 基本使用

import javax.inject.Inject;

public class Student {

@Inject
public Student() {
}
}

编译之后会产生成如下代码:

//...\build\generated\source\apt\debug\com\york\dragger2\bean\Student_Factory.java

import dagger.internal.Factory;

public final class Student_Factory implements Factory<Student> {
private static final Student_Factory INSTANCE = new Student_Factory();

@Override
public Student get() {
return new Student();
}

public static Student_Factory create() {
return INSTANCE;
}

public static Student newInstance() {
return new Student();
}
}

通过 ​​@Inject​​​ 注解了一个类的构造方法后,可以让编译器帮助我们产生一个对应的 ​​Factory​​​ 类,通过这个工厂类我们可以通过简单的 ​​get()​​​ 方法获取到 ​​Student​​ 对象!

2.1 创建一个Activity 调用Student

public class MainActivity extends AppCompatActivity {

@BindView(R.id.btn)
Button btn;

@Inject
User mUser;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
}

@OnClick(R.id.btn)
void btnClicked(){
System.out.println("======================");
btn.setText(mUser.toString());
}
}

直接运行代码,并点击Button,很遗憾,直接报空指针异常。

显然,和平常使用的结果一样,​​@Inject​​​ 并没有帮助我们初始化对应的 ​​Student​​​ 对象,或者说,我们的 ​​Activity​​​ 并没有使用刚才我们看到的 ​​Student_Factory​​​ 类,不过也可以理解,我们并没有建立​​Activity​​​ 和 ​​Student_Factory​​ 类之间的关系嘛。

2.2 曲线救国,Component接口

我们接下来创建一个Module类以及一个Component接口:

import dagger.Component;

@Component(modules = SimpleModule.class)
public interface SimpleComponent {
void inject(MainActivity activity);
}
import dagger.Module;

@Module
public class SimpleModule {

private MainActivity activity;

public SimpleModule(MainActivity activity) {
this.activity = activity;
}
}

突然出现的这两个类可以称得上是莫名其妙,因为我们从代码上来看并不知道这对于Student和Activity之间关系有什么实质性的进展,但假如我们这时在Activty中添加这一段代码:

 @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

ButterKnife.bind(this);

//Here
DaggerSimpleComponent.builder()
.simpleModule(new SimpleModule(this))
.build()
.inject(this);
}

再次点击就可以正常运行代码了。显然,被 ​​@Inject​​​ 的 ​​Student​​​ 类被成功依赖注入到了 ​​Activity​​​中,我们接下来就可以肆无忌惮使用这个 ​​Student​​ 对象了!

3. Module 和 Component 的意义

我们可以暂时这样理解 Module,它的作用就好像是快递的箱子,里面装载的是我们想要的商品,我们在 ​Module​ 中放入什么商品,快递员 ​Component​ 将箱子送到我们家(​Activity​ 容器),我们就可以直接使用里面的商品啦!

为了展示 ​​Module​​​ 的作用,我们重写 ​​Student​​​ 类,取消了 ​​@Inject​​ 注解:

public class Student {

public Student() {
}

}

​Module​​ 中添加这样一段代码:

@Module
public class SimpleModule {

private SimpleModule activity;

public SimpleModule (MainActivity activity) {
this.activity = activity;
}
//下面为新增代码:
@Provides
Student provideStudent(){
return new Student();
}
}

然后 ​​Component​​​ 不变,​​Activity​​ 中仍然是这样:

DaggerSimpleComponent.builder()
.simpleModule(new SimpleModule(this))
.build()
.inject(this);

然后运行,我们发现,仍然可以点击使用 ​​Student​​ 对象!

原因很简单,虽然 ​​@Inject​​​ 注解取消了,但是我们已经在快递箱子(​​Module​​​)中通过 ​​@Providers​​​放入了一个 ​​Student​​对象,然后让快递员(Component)送到了家中(Activity),我们当然可以使用Student对象了!

4. 小结

经过简单的使用 ​​Dagger2​​,我们已经可以基本有了以下了解:

  • ​@Inject​​​: 注入,被注解的构造方法会自动编译生成一个 ​​Factory​​ 工厂类提供该类对象。
  • ​@Component​​: 注入器,类似快递员,作用是将产生的对象注入到需要对象的容器中,供容器使用。
  • ​@Module​​​: 模块,类似快递箱子,在 ​​Component​​ 接口中通过 ​​@Component(modules = xxxx.class)​​, 将容器需要的商品封装起来,统一交给快递员(Component),让快递员统一送到目标容器中。

参考链接