Dagger 2: Step To Step
source link: http://www.androidchina.net/4624.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
假设你已经了解 依赖注入 这一概念,只是在如何使用 Dagger 时遇到了一些困扰,因为 Dagger 其实是一个上手难度颇高的库。我试图通过这篇文章解决如何上手这一问题。
目前 Dagger 有两个分支,一个由 Square 维护,一个为 Google 在前者的基础上开出的分支,即 Dagger 2 。关于二者的比较,点击此处 。
本文写作过程中参考了不少优秀的 Dagger 文章,列在文章末尾。
在此一并感谢他们的工作!
Dagger
在引入 Dagger 之前,我们需要了解一些基础概念。Dagger 主要分三块:
- @Inject:需要注入依赖的地方,Dagger 会构造一个该类的实例并满足它所需要的依赖;
- @Module:依赖的提供者,Module 类中的方法专门提供依赖,并用 @Provides 注解标记;
- @Component:依赖的注入者,是 @Inject 和 @Module 的桥梁,它从 @Module 中获取依赖并注入给 @Inject。
对于以上关系,一句话解释就是:模块(Module)负责提供依赖,组件(Component)负责注入依赖。
Sourcecode
源码放在 Github: DaggerDemo
Gradle
1.project/build.gradle
buildscript {
...
dependencies {
...
classpath
'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
2.project/app/build.gradle
apply plugin:
'com.android.application'
apply plugin:
'com.neenbedankt.android-apt'
android {
...
}
dependencies {
...
//Required by Dagger2
apt
'com.google.dagger:dagger-compiler:2.0.2'
compile
'com.google.dagger:dagger:2.0.2'
// Dagger 2 中会用到 @Generated 注解,而 Android SDK 中没有 javax.anotation.Generated.class,所以在 Android 项目要添加此句
provided
'org.glassfish:javax.annotation:10.0-b28'
}
Example
Demo 实现一个简单的 ListView
显示字符串列表
创建 UserAdapter
类,并在构造函数前添加 @Inject 注解。这样,Dagger 就会在需要获取 UserAdapter
对象时,调用这个被标记的构造函数,从而生成一个 UserAdapter
对象。
public
class
UserAdapter
extends
BaseAdapter {
private
LayoutInflater inflater;
private
List<String> users;
@Inject
public
UserAdapter(Context ctx, List<String> users) {
this
.inflater = LayoutInflater.from(ctx);
this
.users = users;
}
...
}
需要注意的是:如果构造函数含有参数,Dagger 会在调用构造对象的时候先去获取这些参数(不然谁来传参?),所以你要保证它的参数也提供可被 Dagger 调用到的生成函数。Dagger 可调用的对象生成方式有两种:一种是用 @Inject 修饰的构造函数,上面就是这种方式。另外一种是用 @Provides 修饰的函数,下面会讲到。参考:Dagger 源码解析
构建 Module,提供 Context 和 List<String> 依赖,如此, Dagger 生成 UserAdapter 时所需要的依赖就从这里获取。
@Module
public
class
UserModule {
private
static
final
int
COUNT =
10
;
private
final
Context context;
public
UserModule(Context context) {
this
.context = context;
}
@Provides
@ActivityScope
Context provideActivityContext() {
return
context;
}
@Provides
@ActivityScope
List<String> provideUsers() {
List<String> users =
new
ArrayList<>(COUNT);
for
(
int
i =
0
; i < COUNT; i++) {
users.add(
"item "
+ i);
}
return
users;
}
}
@ActivityScope 是一个自定义的范围注解,作用是允许对象被记录在正确的组件中,当然这些对象的生命周期应该遵循 Activity 的生命周期。
import
java.lang.annotation.Retention;
import
static
java.lang.annotation.RetentionPolicy.RUNTIME;
import
javax.inject.Scope;
@Scope
@Retention
(RUNTIME)
public
@interface
ActivityScope {
}
构建 Component,负责注入依赖
@ActivityScope
@Component
(modules = {UserModule.
class
})
public
interface
UserComponent {
void
inject(MainActivity activity);
}
注意:这里必须是真正消耗依赖的类型 MainActivity
,而不可以写成其父类,比如 Activity
,否则会导致注入失败。(参考:使用Dagger 2进行依赖注入)
完成依赖注入
public
class
MainActivity
extends
AppCompatActivity {
...
@Inject
UserAdapter adapter;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
..
// 完成注入
DaggerUserComponent.builder()
.userModule(
new
UserModule(
this
))
.build()
.inject(
this
);
listView.setAdapter(adapter);
}
}
如果找不到 DaggerUserComponent
类,你需要先编译一下整个项目。这是因为 Dagger 是在编译时生成必要的元素,编译时 Dagger 会处理我们的注解,为 @Components 生成实现并命名为 Dagger$${YouComponentClassName}
,如 UserComponent
->DaggerUserComponent
。你可以在 app/build/generated/source/apt
下找到相关的类。
实际上,调用 inject 方法最终调用的是以下这样一段代码,更多细节可以查看源码。
@Override
public
void
injectMembers(MainActivity instance) {
if
(instance ==
null
) {
throw
new
NullPointerException(
"Cannot inject members into a null reference"
);
}
supertypeInjector.injectMembers(instance);
instance.adapter = adapterProvider.get();
}
Dagger too
- @Inject 和 @Provide 两种依赖生成方式的区别:
- @Inject 用于注入可实例化的类,@Provides 可用于注入所有类
- @Inject 可用于修饰属性和构造函数,可用于任何非 Module 类,@Provides 只可用于用于修饰非构造函数,并且该函数必须在某个Module内部
- @Inject 修饰的函数只能是构造函数,@Provides 修饰的函数必须以 provide 开头
- Dagger 的其他注解:
- @Scope: Dagger 可以通过自定义注解限定注解作用域,参考前面的 @ActivityScope。
- @Qualifier:限定符,当类的类型不足以鉴别一个依赖的时候,我们就可以使用这个注解来区分。例如:在 Android 中,我们会需要不同类型的 Context,所以我们可以定义 @Qualifier 注解
@ForApplication
和@ForActivity
,这样当注入一个 Context 的时候,我们就可以告诉 Dagger 我们想要哪种类型的 Context。 - @Singleton:单例模式,依赖的对象只会被初始化一次
- Dagger 的实际应用:本例只是一个上手教程,辅助理解 Dagger 的原理及使用方式,具体的项目应用可以参考 Reference 中第 3 条的 Avengers 的源码 。
Reference
原文:http://www.jianshu.com/p/7505d92d7748
转载请注明:Android开发中文站 » Dagger 2: Step To Step
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK