Dragger代码实现
转自:http://www.apkbus.com/blog-705730-60436.html
在工程中引入Dagger
如果想使用Dagger的话,需要添加两个函数库:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.squareup.dagger:dagger:1.2.+'
provided 'com.squareup.dagger:dagger-compiler:1.2.+'
}
第一个是Dagger函数库,第二个是Dagger编译器函数库,它会创建注入依赖所需的类。通过创建预编译的类可以避免大部分的反射操作。由于我们只需要Dagger编译器函数库来编译工程,在应用中不会使用到它,因此我们把它标记为provided,这样在最终的apk中就不会包含这个函数库了。
创建第一个module
Modules是使用Dagger经常碰到的概念,所以你需要习惯它们。Modules是提供依赖注入时所需对象实例的类,它们通过@Module注解来修饰类。还有其他一些额外参数可能需要配置,但我们会在使用到的时候再进行介绍。
创建一个名为AppModule的类,假设用于提供Application Context。为Application Context提供简单的访问入口通常是有趣的。我创建继承自Application的类App,并添加到AndroidManifest文件中。
@Module(
injects = {
App.class
}
)
public class AppModule {
private App app;
public AppModule(App app) {
this.app = app;
}
@Provides @Singleton public Context provideApplicationContext() {
return app;
}
}
上面涉及到哪些新知识呢?
- @Module:把这个类标识为Dagger module。 injects:标识module将要注入这个类的任何依赖。我们需要明确指定将直接注入到对象图中的那些类,这将很快会讲到。
- @Providers:标识函数作为注入提供者,函数名并不重要,它只依赖于所提供的类类型。
- @Singleton:如果标识为Singleton,那这个函数会一直返回相同的对象实例,这比常规的单例好很多。否则,每次注入类型都会得到一个新的实例。在这个例子中,由于我们没有创建新实例,而是返回已经存在的实例,因此即使不把函数标识为Singleton,每次调用还是会返回相同的实例的,但这样能够更好地说明提供者到底做了什么。Application实例是唯一的。
为什么常规的单例是不好的
单例可能是一个工程能够具有的最危险的依赖了。首先,由于我们没有创建实例,因此很难知道要在什么地方使用它,因此具有“隐藏依赖”。另外,我们没有办法通过mock来测试它,或者以另外的模块替换它,因此代码变得难以维护,测试和进化。被注入的单例,相反,具有单例的优势(唯一的实例),同时,由于我们可以在任何时候创建新的实例,因此很容易mock或者通过子类化或者使其实现一个公有接口来使用另一个代码片段替换它。
我们将在一个新的名为domain的包里面创建另外一个module。在每个架构层拥有至少一个module是很有用的。这个module将提供一个统计管理器,在app启动时通过显示一个Toast来抛出一个事件。在实际的工程中,这个管理器可能调用任何统计服务例如Google Analytics。
@Module(
complete = false,
library = true
)
public class DomainModule {
@Provides @Singleton public AnalyticsManager provideAnalyticsManager(Application app){
return new AnalyticsManager(app);
}
}
通过把这个module指明为未完成,表示这个module的某些依赖需要另外一个module来提供。也就是AppModule里面的Application。当我们从一个依赖注入请求这个AnalyticsManager时,dagger将会使用这个函数,并会检测到它需要另外一个依赖:Application,这会通过向对象图发起请求来获得。我们同时需要把module指明为library,因为dagger编译器会检测到AnalyticsMananger没有被它自身或者它的注入类所使用。对于AppModule来说,DomainModule就是一个库模块。
我们将指定AppModule会包含DomainModule,因此返回AppModule类,修改代码如下:
@Module(
injects = {
App.class
},
includes = {
DomainModule.class
}
)
public class AppModule {
...
}
includes属性正是用来实现这个目的的。
创建对象图
对象图是所有依赖存在的地方。对象图包含被创建的实例,并能够把这些实例注入到相应的对象中。
在前面的例子中(AnalyticsManager)我们看到了经典的依赖注入,注入是通过构造函数参数传递的。但在Android中有的类(Application,Activity)我们对构造函数没有控制权,因此我们需要另外一种方式来注入依赖。
ObjectGraph创建和直接注入的组合方式在App类中可以看到。主对象图在Application类中创建并被注入以获得依赖。
public class App extends Application {
private ObjectGraph objectGraph;
@Inject AnalyticsManager analyticsManager;
@Override public void onCreate() {
super.onCreate();
objectGraph = ObjectGraph.create(getModules().toArray());
objectGraph.inject(this);
analyticsManager.registerAppEnter();
}
private List<Object> getModules() {
return Arrays.<Object>asList(new AppModule(this));
}
}
我们通过@Inject注解来指明谁是依赖,这些依赖项必须是public或者default范围的,以便dagger可以给它们赋值。我们创建了一个modules数组(我们只有一个module,DomainModule是包含在AppModule里面的),并通过它来创建一个ObjectGraph实例。然后,我们手动注入App实例,这样之后,依赖就被注入了,因此可以直接调用AnalyticsManager的函数了。
结论
现在你掌握了Dagger的基础用法。ObjectGraph和Modules是有效的使用Dagger必须掌握的最有意思的组件。还有其他更多的工具例如懒注入或者provider注入,在Dagger网页上面有介绍,但在你熟练掌握本文所介绍的知识之前,我不建议你深入研究它们。
git示例源码:https://github.com/ppamorim/Dragger
Dragger代码实现的更多相关文章
- android ListView和GridView拖拽移位实现代码
关于ListView拖拽移动位置,想必大家并不陌生,比较不错的软件都用到如此功能了.如:搜狐,网易,百度等,但是相比来说还是百度的用户体验较好,不偏心了,下面看几个示例: 首先 ...
- 日期格式代码出现两次的错误 ORA-01810
错误的原因是使用了两次MM . 一.Oracle中使用to_date()时格式化日期需要注意格式码 如:select to_date('2005-01-01 11:11:21','yyyy-MM-dd ...
- 可爱的豆子——使用Beans思想让Python代码更易维护
title: 可爱的豆子--使用Beans思想让Python代码更易维护 toc: false comments: true date: 2016-06-19 21:43:33 tags: [Pyth ...
- iOS代码规范(OC和Swift)
下面说下iOS的代码规范问题,如果大家觉得还不错,可以直接用到项目中,有不同意见 可以在下面讨论下. 相信很多人工作中最烦的就是代码不规范,命名不规范,曾经见过一个VC里有3个按钮被命名为button ...
- Jquery的点击事件,三句代码完成全选事件
先来看一下Js和Jquery的点击事件 举两个简单的例子 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN&q ...
- redux-amrc:用更少的代码发起异步 action
很多人说 Redux 代码多,开发效率低.其实 Redux 是可以灵活使用以及拓展的,经过充分定制的 Redux 其实写不了几行代码.今天先介绍一个很好用的 Redux 拓展-- redux-amrc ...
- 编写高质量代码:改善Java程序的151个建议(第5章:数组和集合___建议75~78)
建议75:集合中的元素必须做到compareTo和equals同步 实现了Comparable接口的元素就可以排序,compareTo方法是Comparable接口要求必须实现的,它与equals方法 ...
- 使用 .NET WinForm 开发所见即所得的 IDE 开发环境,实现不写代码直接生成应用程序
直接切入正题,这是我09年到11年左右业余时间编写的项目,最初的想法很简单,做一个能拖拖拽拽就直接生成应用程序的工具,不用写代码,把能想到的业务操作全部封装起来,通过配置的方式把这些业务操作组织起来运 ...
- jsp前端实现分页代码
前端需要订一page类包装,其参数为 private Integer pageSize=10; //每页记录条数=10 private Integer totalCount; //总记录条数 priv ...
随机推荐
- PHP应用程序的安全性
无论在开发中,还是在面试时或者技术讨论时,安全性都是需要深入了解及掌握的. 目标 本教程目标是使您了解应该如何保护自己构建的 Web 应用程序.讲解如何防御最常见的安全威胁:SQL 注入.操纵 GET ...
- Win7-IIS7下运行PHP网站(以配置好的drupal网站为例)
0.前提:IIS7已启用. drupal网站配置文件web.config中用到了“简洁链接”(URL重写),所以,还需要事先安装URL重写模块. URL重写模块(url rewrite)下载地址: r ...
- 查看 yum 安装软件包的路径
yum:列出已安装的安装包 [root@localhost ~]# yum list | grep mysql akonadi-mysql.x86_64 1.9.2-4.el7 base apr-ut ...
- 基于jsp+servlet图书管理系统之后台用户信息修改操作
上一篇的博客写的是查询操作,且附有源码和数据库,这篇博客写的是修改操作,附有从头至尾写的代码(详细的注释)和数据库! 此次修改操作的源码和数据库:http://download.csdn.net/de ...
- jQuery全选、反选、全不选
原文链接:https://yq.aliyun.com/articles/33443 HTML内容部分: <ul id="items"> <li> <l ...
- 哟西,CLOUDSTACK第一步,搞定
安装了N十次,找个RESET SERVER的脚本.
- eclipse能够自动提示变量名.
打开 Eclipse -> Window -> Perferences -> Java -> Editor -> Content Assist,在右边最下面一栏找到 au ...
- android 自定义titlebar
首先,修改标题栏的宽度和背景,在style.xml中添加: <style> <item name="android:background">@drawabl ...
- UVA253 Cube painting(数学)
题目链接. 分析: 用的<训练指南>上的方法.详见P17. 从6个面中选一个做顶面,再从剩下的4个面中选1个做正面,则此正方体唯一确定. 需要枚举共6*4=24种. #include &l ...
- js类型判断及鸭式辨型
目录 instanceof constructor 构造函数名字 鸭式辨型 三种检测对象的类方式: instanceof.constructor .构造函数名字 用法如下: 1)instanceof ...