Dagger 2: Step To Step
原文链接:http://www.jianshu.com/p/7505d92d7748
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
假设你已经了解 依赖注入 这一概念,只是在如何使用 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
project/build.gradle
buildscript {
... dependencies {
... classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}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
Dagger 2: Step To Step的更多相关文章
- Step by step Dynamics CRM 2011升级到Dynamics CRM 2013
原创地址:http://www.cnblogs.com/jfzhu/p/4018153.html 转载请注明出处 (一)检查Customizations 从2011升级到2013有一些legacy f ...
- Step by Step 创建一个新的Dynamics CRM Organization
原创地址:http://www.cnblogs.com/jfzhu/p/4012833.html 转载请注明出处 前面演示过如何安装Dynamics CRM 2013,参见<Step by st ...
- Step by step Install a Local Report Server and Remote Report Server Database
原创地址:http://www.cnblogs.com/jfzhu/p/4012097.html 转载请注明出处 前面的文章<Step by step SQL Server 2012的安装 &g ...
- Step by step Dynamics CRM 2013安装
原创地址:http://www.cnblogs.com/jfzhu/p/4008391.html 转载请注明出处 SQL Server可以与CRM装在同一台计算机上,也可安装在不同的计算机上.演示 ...
- Step by step 活动目录中添加一个子域
原创地址:http://www.cnblogs.com/jfzhu/p/4006545.html 转载请注明出处 前面介绍过如何创建一个域,下面再介绍一下如何在该父域中添加一个子域. 活动目录中的森林 ...
- SQL Server 维护计划实现数据库备份(Step by Step)(转)
SQL Server 维护计划实现数据库备份(Step by Step) 一.前言 SQL Server 备份和还原全攻略,里面包括了通过SSMS操作还原各种备份文件的图形指导,SQL Server ...
- 转:eclipse以及step into step over step return的区别
首先来讲一下step into step over step return的区别: step into就是单步执行,遇到子函数就进入并且继续单步执行:(F5) step over是在单步执行时,在函数 ...
- [转]Bootstrap 3.0.0 with ASP.NET Web Forms – Step by Step – Without NuGet Package
本文转自:http://www.mytecbits.com/microsoft/dot-net/bootstrap-3-0-0-with-asp-net-web-forms In my earlier ...
- EF框架step by step(7)—Code First DataAnnotations(2)
上一篇EF框架step by step(7)—Code First DataAnnotations(1)描述了实体内部的采用数据特性描述与表的关系.这一篇将用DataAnnotations描述一下实体 ...
- EF框架step by step(6)—处理实体complex属性
上一篇的中介绍过了对于EF4.1框架中,实体的简单属性的处理 这一篇介绍一下Code First方法中,实体Complex属性的处理.Complex属性是将一个对象做为另一个对象的属性.映射到数据库中 ...
随机推荐
- java 注解Annotation
什么是注解? 注解,顾名思义,注解,就是对某一事物进行添加注释说明,会存放一些信息,这些信息可能对以后某个时段来说是很有用处的. java注解又叫java标注,java提供了一套机制,使得我们可以对 ...
- javascript学习笔记20160121-css选择器
元素可以用id.标签名或类来描述: 更一般的,元素可以基于属性来选取: 这些基本的选择器可以组合使用: 选择器可以指定文档结构(重要,之前一直不太明白>的使用): 选择器可以组合起来选取多个或多 ...
- OpenCV(3)-图像resize
在图像处理过程中,有时需要把图像调整到同样大小,便于处理,这时需要用到图像resize() 原函数 void resize(InputArray src, OutputArray dst, Size ...
- 【JSP&Servlet学习笔记】5.Servlet进阶AIP、过滤器与监听器
Servlet接口上,与生命周期及请求服务相关的三个方法是init().service()与destory()方法.当Web容器加载Servlet类并实例化之后,会生成ServletConfig对象并 ...
- hdu 5056 Boring count
贪心算法.需要计算分别以每个字母结尾的且每个字母出现的次数不超过k的字符串,我们设定一个初始位置s,然后用游标i从头到尾遍历字符串,使用map记录期间各个字母出现的次数,如果以s开头i结尾的字符串满足 ...
- table隔行换色
以前做表格隔行换色,是在tr上添加不同的背景色,但在程序开发的过程需要做判断,不够方便,而且生成的代码也比较多,现在的需求逐渐修改为JQ去控制简洁的表格去显示隔行换色 <script type= ...
- javaweb——总结
day01XML上 1.XML的作用 2.XML的基本语法 3.DTD约束 4.DTD的基本语法(看懂DTD就ok) 5.XML的解析方式:原理 6.JAXP的DO ...
- js组件开发流程
html代码 <div id="div1"></div> <div id="div2"></div> <d ...
- 关于实现判断用户是在PC端和还是移动端访问。
最近一直在忙我们团队的项目“咖啡之翼”,在这个项目中,我们为移动平台提供了一个优秀的体验.伴随Android平台的红火发展.不仅带动国内智能手机行业,而且许多国内开发者也开始投身于Android移动终 ...
- java 中的 & | ~ ^ 运算符分析
1.与运算符与运算符用符号“&”表示,其使用规律如下:两个操作数中位都为1,结果才为1,否则结果为0,例如下面的程序段.public class data13{public static vo ...