转自: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代码实现的更多相关文章

  1. android ListView和GridView拖拽移位实现代码

    关于ListView拖拽移动位置,想必大家并不陌生,比较不错的软件都用到如此功能了.如:搜狐,网易,百度等,但是相比来说还是百度的用户体验较好,不偏心了,下面看几个示例:             首先 ...

  2. 日期格式代码出现两次的错误 ORA-01810

    错误的原因是使用了两次MM . 一.Oracle中使用to_date()时格式化日期需要注意格式码 如:select to_date('2005-01-01 11:11:21','yyyy-MM-dd ...

  3. 可爱的豆子——使用Beans思想让Python代码更易维护

    title: 可爱的豆子--使用Beans思想让Python代码更易维护 toc: false comments: true date: 2016-06-19 21:43:33 tags: [Pyth ...

  4. iOS代码规范(OC和Swift)

    下面说下iOS的代码规范问题,如果大家觉得还不错,可以直接用到项目中,有不同意见 可以在下面讨论下. 相信很多人工作中最烦的就是代码不规范,命名不规范,曾经见过一个VC里有3个按钮被命名为button ...

  5. Jquery的点击事件,三句代码完成全选事件

    先来看一下Js和Jquery的点击事件 举两个简单的例子 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN&q ...

  6. redux-amrc:用更少的代码发起异步 action

    很多人说 Redux 代码多,开发效率低.其实 Redux 是可以灵活使用以及拓展的,经过充分定制的 Redux 其实写不了几行代码.今天先介绍一个很好用的 Redux 拓展-- redux-amrc ...

  7. 编写高质量代码:改善Java程序的151个建议(第5章:数组和集合___建议75~78)

    建议75:集合中的元素必须做到compareTo和equals同步 实现了Comparable接口的元素就可以排序,compareTo方法是Comparable接口要求必须实现的,它与equals方法 ...

  8. 使用 .NET WinForm 开发所见即所得的 IDE 开发环境,实现不写代码直接生成应用程序

    直接切入正题,这是我09年到11年左右业余时间编写的项目,最初的想法很简单,做一个能拖拖拽拽就直接生成应用程序的工具,不用写代码,把能想到的业务操作全部封装起来,通过配置的方式把这些业务操作组织起来运 ...

  9. jsp前端实现分页代码

    前端需要订一page类包装,其参数为 private Integer pageSize=10; //每页记录条数=10 private Integer totalCount; //总记录条数 priv ...

随机推荐

  1. HTML&CSS基础学习笔记1.33-元素选择器

    元素选择器 最常见的 CSS 选择器是元素选择器.换句话说,文档的元素就是最基本的选择器: p { text-indent:10px; color:blue; } 什么情况下使用元素选择器,一般我们这 ...

  2. UVA 1600 Patrol Robot(机器人穿越障碍最短路线BFS)

    UVA 1600 Patrol Robot   Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu   ...

  3. SCJP_104——题目分析(2)

    3. public class IfTest{ public static void main(String args[]){ int x=3; int y=1; if(x=y) System.out ...

  4. maven3.0

    Maven入门教程 1.1. 介绍.环境配置 1.1.1. Maven介绍 Maven是一个采用纯Java编写的开源项目管理工具, Maven采用了一种被称之为Project Object Model ...

  5. Scut:Redis 资源管理器

    核心文件是:RedisConnectionPool.cs 对象池类的通用泛型封装:ObjectPoolWithExpire<T> 1. 主要变量 private static ICache ...

  6. Extjs4.1.x使用Application动态按需加载MVC各模块

    我们知道Extjs4之后提出了MVC模块开发,将以前肥厚的js文件拆分成小的js模块[model\view\controller\store\form\data等],通过controller拼接黏合, ...

  7. 一步一步学习SignalR进行实时通信_7_非代理

    原文:一步一步学习SignalR进行实时通信_7_非代理 一步一步学习SignalR进行实时通信\_7_非代理 SignalR 一步一步学习SignalR进行实时通信_7_非代理 前言 代理与非代理 ...

  8. Linux2.6内核--对块IO层操作的讨论

          当一个块被调入内存时(也就是说,在读入后或等待写出时),它要存储在缓冲区中.每个缓冲区与一个块对应,它相当于是磁盘块在内存中的表示.块包含一个或多个扇区,但大小不能超过一页,所以一页可以容 ...

  9. BZOJ1629: [Usaco2007 Demo]Cow Acrobats

    1629: [Usaco2007 Demo]Cow Acrobats Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 601  Solved: 305[Su ...

  10. HDOJ(HDU) 1977 Consecutive sum II(推导、、)

    Problem Description Consecutive sum come again. Are you ready? Go ~~ 1 = 0 + 1 2+3+4 = 1 + 8 5+6+7+8 ...