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),让快递员统一送到目标容器中。
参考链接