本文介绍了Dagger 2 中@Inject、@Component、@Module和@Provides以及@Module和@Binds的使用。
《七步诗》
煮豆燃豆萁,豆在釜中泣。
本是同根生,相煎何太急?
-两汉,曹植
前言
Dagger 2 在 Android 上的使用(一)
Dagger 2 在 Android 上的使用(二)
Dagger 2 在 Android 上的使用(三)
Dagger 2 在 Android 上的使用(四)
Dagger 2 在 Android 上的使用(五)
在上一篇文章中我们介绍了Dagger2在android上的简单用法,接下来我们对Dagger2中提供的注解进行详细的使用说明。
注解@Inject和注解@Component
使用注解@Inject
和注解@Component
可以完成简单依赖注入。
先来看一个未使用Dagger2的例子,稍候使用Dagger2完成依赖注入。
1 | public class People { |
在Activity中实例化此类并调用相应方法:
1 | public class PeopleActivity extends Activity { |
使用Dagger2完成依赖注入,People类需要添加一个空的构造方法并使用@Inject
进行注解:
1 | public class People { |
注解@Inject
用在构造方法上表示告诉Dagger 2可以使用此构造方法提供需要的实例。
添加一个@Component
注解的接口类,这会生成以Dagger为前缀的Component实现类。注解@Component
只能用在接口或抽象类上。
1 | @Component |
在Activity中使用@Inject
对People进行注解,注意类型不能是private的。然后编译使用生成的DaggerPeopleComponent类进行依赖注入。1
2
3
4
5
6
7
8
9
10
11
12public class PeopleActivity extends Activity{
@Inject
People people;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DaggerPeopleComponent.create().inject(this);
Log.d("debug", people.doWhat());
}
}
然后我们看一下生成的类是如何实现依赖注入的。在Activity中的成员变量people添加的@Inject
注解生成了对应的MembersInjector类,用于给对应注入成员变量赋值。
1 | public final class PeopleActivity_MembersInjector implements MembersInjector<PeopleActivity> { |
定义的Component接口类生成了对应的实现类,当我们在Activity中调用inject方法时完成了成员变量的赋值。
1 | public final class DaggerPeopleComponent implements PeopleComponent { |
PS:从生成的代码中我们发现了一个People_Factory类用于People的实例化,但目前并没有用到。
这样我们使用注解@Inject
和注解@Component
就完成了简单的依赖注入。
注解@Inject
是JSR-330标准中的一部分,标记那些应该被依赖注入框架提供的依赖。
注解@Inject
用在构造器上有两种作用:
- 表示可以使用此构造器构建对象
- 注入构造器所需要的参数的依赖
例如People依赖Tools类,这样也会完成Tools的注入。
1 | public class People { |
注解@Inject
可以用在成员变量完成依赖注入,正如上面看到的例子,也可以用在成员方法上完成依赖注入,例如:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public class PeopleActivity extends Activity{
private People people;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DaggerPeopleComponent.create().inject(this);
Log.d("debug", people.doWhat());
}
@Inject
public void setPeople(People people) {
this.people = people;
}
}
然后我们再来看一下生成的代码:
1 | public final class DaggerPeopleComponent implements PeopleComponent { |
成员注入:
1 | public final class PeopleActivity_MembersInjector implements MembersInjector<PeopleActivity> { |
从生成的代码来看使用成员变量注入和成员方法注入基本没有任何区别,这两者都是在调用注入方法时完成变量的赋值。推荐大家使用更简单的成员变量注入方法。
注解@Module和注解@Provides
使用@Inject标注构造方法这种方式会有以下限制:
- 第三方库无法注入
- 接口和抽象类无法注入
针对上述限制我们可以使用注解@Module
和注解@Provides
完成注入,接下来看一个抽象类和接口注入的实例:
1 | public abstract class People { |
新建Module类用于提供相应实例:
1 | @Module |
在Component类指定Module类:
1 | @Component(modules = PeopleModule.class) |
在Activity中进行注入:
1 | public class PeopleActivity extends Activity{ |
Dagger2自动生成的类,用于提供People实例:
1 | public final class PeopleModule_ProvidePeopleFactory implements Factory<People> { |
Dagger2自动生成的类,用于提供PeopleContract.Presenter实例:
1 | public final class PeopleModule_ProvidePeoplePresenterFactory |
在Component类中进行了调用:
1 | public final class DaggerPeopleComponent implements PeopleComponent { |
注解@Module和注解@Binds
对于抽象类和接口的注入,我们还可以使用注解@Binds
实现,使用注解@Binds
有如下要求:
- 必须用在Module里的抽象方法
- 必须为抽象方法
- 必须有一个参数,参数类型可以分配给方法的返回类型
对上面的例子进行下修改:
1 | @Module |
这时我们需要给提供的注入类型添加空的构造方法,然后添加@Inject
注解:
1 | public class Student extends People { |
生成的代码;
1 | public final class DaggerPeopleComponent implements PeopleComponent { |
这可以实现和使用@Provides
注解相同的功能,这里推荐使用@Binds
注解实现注入功能。
总结
- 使用注解
@Inject
和注解@Component
可以完成简单的依赖注入 - 注解
@Component
只能用在接口或抽象类上,会自动生成以Dagger为前缀的实现类 - 注解
@Inject
用在构造方法上表示可以使用此构造方法提供需要的实例,如果构造方法包含参数,也会对其参数完成注入 - 注解
@Inject
可以用在非private的成员变量和成员方法上完成依赖注入,推荐使用成员变量注入的方式 - 对于无法在构造方法上使用
@Inject
注解提供实例的情况,可以使用注解@Module
和注解@Provides
提供依赖实例,注意需要在Component类指定Module类 - 对于抽象类和接口的注入,也可以使用注解
@Module
和注解@Binds
实现,注解@Binds
用在抽象方法上,返回类型为需要注入的类型,包含一个可以分配给返回类型的参数,推荐使用注解@Binds
完成依赖注入,注意需要在参数的构造方法上添加@Inject
注解以提供对应实例
参考
- https://google.github.io/dagger/
- https://www.jianshu.com/p/24af4c102f62
- http://www.cnblogs.com/tiantianbyconan/p/5092083.html