什么是Dagger2

Dagger是为Android和Java平台提供的一个完全静态的,在编译时进行依赖注入的框架,原来是由Square公司维护,现在由Google维护。

我们知道Dagger是一个依赖注入的框架,那么什么是依赖注入呢?

我们在activity中有可能会用到很多很多的类,这些类要在activity中进行实例化,这样就导致我们的activity非常依赖这么多的类,这样的程序耦合非常

严重,不便于维护和扩展,有什么办法可以不去依赖这些类呢,这时候就需要有一个容器(IoC),将这些类放到这个容器里并实例化,我们activity在用

到的时候去容器里面取就可以了,我们从依赖类到依赖这个容器,实现了解耦,这就是我所理解的依赖注入,即所谓控制反转;

简单的说 Dagger就是用来创造这个容器,所有需要被依赖的对象在Dagger的容器中实例化,并通过Dagger注入到合适的地方,实现解耦,MVP框架就是为解耦而生,因此MVP和Dagger是绝配;

举个栗子?

通常情况下我们引用一个类的做法:

我们先定义一个简单的类:

 public class User {
private String name; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}

在Activity中对其操作

 private void initData() {

         User user = new User();

         user.setName("测试");
}

以上是最普通的用法

接下来我们来看Dagger2的用法

我们先来配置一下Dagger2

首先在项目的 build.gradle:

 dependencies {
classpath 'com.android.tools.build:gradle:1.5.0'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
classpath 'me.tatarka:gradle-retrolambda:3.2.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}

然后是APP的 build.gradle

 apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
apply plugin: 'me.tatarka.retrolambda'
android {
compileSdkVersion 23
buildToolsVersion "23.0.1" defaultConfig {
applicationId "jiao.com.jiaoproject"
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
} compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
} } dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.3.0'
compile 'com.android.support:design:23.3.0'
apt 'com.google.dagger:dagger-compiler:2.2'
provided 'org.glassfish:javax.annotation:10.0-b28'
compile 'com.google.dagger:dagger:2.2'
compile 'com.jakewharton:butterknife:7.0.1'
compile 'com.squareup.okhttp3:logging-interceptor:3.3.0'
}

首先

 public class User {
private String name; @Inject
public User() {
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}

发现有什么变化了没?@Inject是什么东东?待会我们来说;

接着我们看怎么使用

     @Inject
User user; private void initData() { user.setName("测试");
}

这时候我们允许程序发现空指针了;因为还缺少一个东西;

 @Component
public interface ActivityComponent { void inject(MainActivity MainActivity);
}

加上这个类之后 并且在Activity中对其初始化 完整代码如下:

  @Inject
User user; private void initData() {
DaggerActivityComponent.builder().build().inject(this);
user.setName("测试");
}

这时候发现我们的user对象可以正常使用了;看上去感觉挺复杂的,但是对于大型项目引用的类过多的时候,Dagger的优势就体现出来了;

接下来我一一解答你们的疑惑;

首先我们来了解这几个基础概念:

  • @Inject Inject主要有两个作用,一个是使用在构造函数上,通过标记构造函数让Dagger2来使用(Dagger2通过Inject标记可以在需要这个类实 例的时候来找到这个构造函数并把相关实例new出来)从而提供依赖,另一个作用就是标记在需要依赖的变量让Dagger2为其提供依赖。
  • @Provide 用Provide来标注一个方法,该方法可以在需要提供依赖时被调用,从而把预先提供好的对象当做依赖给标注了@Injection的变量赋值。provide主要用于标注Module里的方法
  • @Module 用Module标注的类是专门用来提供依赖的。有的人可能有些疑惑,看了上面的@Inject,需要在构造函数上标记才能提供依赖,那么如果我们需要提供 的类构造函数无法修改怎么办,比如一些jar包里的类,我们无法修改源码。这时候就需要使用Module了。Module可以给不能修改源码的类提供依 赖,当然,能用Inject标注的通过Module也可以提供依赖
  • @Component Component一般用来标注接口,被标注了Component的接口在编译时会产生相应的类的实例来作为提供依赖方和需要依赖方之间的桥梁,把相关依赖注入到其中。

看了这些概念我们回到刚才的例子当中:

我们对User的构造函数进行了 @Inject的标注 意思就是告诉Dagger2 如果有谁要使用User这个类,我标注的这个构造函数,你可以直接用来实例化该类;

然后我们在Activity中对User也进行了@Inject的标注 意思是告诉Dagger2 这个类需要被注入,简单的说就是 这个类我要用,你帮我实例化;

细心的读者可能会发现 这样会不会太简单了,是的 是太简单了不太正常,哈哈,上面的例子中还有一个标注@Component 光靠@Inject的标注是不足以完成注入的 我们需要用@Component来完成注入;

上例中被@Component标记的ActivityComponent接口就是一个注入器; void inject(MainActivity MainActivity);的意思是MainActivity中要用到这个注入器然后我们在MainActivity中对注入器进行初始化 DaggerActivityComponent.builder().build().inject(this); 然后Activity中所有被@Inject标记的类,都会通过ActivityComponent来进行初始化;

我们再把上例中的注入过程梳理一下:

1、首先定义一个类User 并在其构造函数用@Inject标注,表示告诉Dagger2这是我的构造函数,如果有地方要用到我,就用该构造函数对我实例化;

2、创建一个@Component标注的注入器接口,并在注入器中使用 void inject(MainActivity MainActivity);来表明哪里要用到注入器;

这里表示MainActivity中要用到该注入器

3、在MainActivity中对注入器进行初始化DaggerActivityComponent.builder().build().inject(this); 初始化后该注入器就可以正常使用了;

4、在MainActivity中对需要注入的类  User用@Inject进行标注,表示该类需要被注入,即实例化;

注意:在代码编写过程中 我们会发现DaggerActivityComponent会不存在,这是因为注入器是在编译的过程中才生成,所以我们在对注入器编写完成后

Make Project 一下就会生成DaggerActivityComponent

————————————————————————————————————————————————————————————————————————————————

现在我们已经明白了@InJect @Component的作用了,接下来我们来研究@Module和@Provide

通过上面的例子我们发现 @Inject是对类的构造函数进行标注来进行实例化的,但是有些类,比如第三方OkHttpClient,我们是无法对其源码进行修改的

即对其构造函数进行标注,这个时候我们就用到了@Module

@Module是什么意思呢 @Module是和@Component配合使用的 意思就是告诉注入器,如果你在实例化对象的时候,没有找到合适的构造函数,你就来我这里找,@Module通常标注一个类,该类里面可以实例化各种类,Component在注入对象的时候先去Module中找,如果找不到就会检查所有被@Inject标注的构造函数;所以我们可以把OkHttpClient放到Module中;

 @Module
public class ActivityMoudle { @Provides
@Singleton
OkHttpClient provideOkHttpClient() {
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); Interceptor apikey = chain -> chain.proceed(chain.request().newBuilder()
.addHeader("apikey", Constants.Api_Key).build()); OkHttpClient okHttpClient = new OkHttpClient.Builder()
.readTimeout(Constants.HTTP_CONNECT_TIMEOUT, TimeUnit.MILLISECONDS)
.connectTimeout(Constants.HTTP_CONNECT_TIMEOUT, TimeUnit.MILLISECONDS)
.addInterceptor(apikey)
.addInterceptor(loggingInterceptor)
.build(); return okHttpClient;
} }

以上代码我们不需要知道是干嘛的,我们只知道该类中的方法返回一个okHttpClient的实例;

一个被@Module标注的类用来返回一个okHttpClient的实例;

我们再来看一下在Component中的代码:

 @Singleton
@Component(modules = ActivityMoudle.class)
public interface ActivityComponent { void inject(MainActivity MainActivity);
}

可以看到标注头多了@Component(modules = ActivityMoudle.class),表示告诉注入器如果你要注入的类没有找到构造函数,你就去ActivityMoudle.class中找

@Provide 用来标注一个方法,告诉注入器,我标注的方法你可以用来提供实例;

@Singleton 顾名思义,标注该实例化的对象为单例

然后我们在Activity直接标注使用就可以了

  @Inject
OkHttpClient okHttpClient;

至此我们有两种方式可以提供依赖,一个是注解了@Inject的构造方法,一个是在Module里提供的依赖,那么Dagger2是怎么选择依赖提供的呢,规则是这样的:

  • 步骤1:查找Module中是否存在创建该类的方法。
  • 步骤2:若存在创建类方法,查看该方法是否存在参数
  • 步骤2.1:若存在参数,则按从步骤1开始依次初始化每个参数
  • 步骤2.2:若不存在参数,则直接初始化该类实例,一次依赖注入到此结束
  • 步骤3:若不存在创建类方法,则查找Inject注解的构造函数,看构造函数是否存在参数

  • 步骤3.1:若存在参数,则从步骤1开始依次初始化每个参数

  • 步骤3.2:若不存在参数,则直接初始化该类实例,一次依赖注入到此结束

这次依赖注入就先写这么多,Dagger结合MVP实现完美的配合,小伙伴们可以自己去研究一下其中的奥妙~

浅析Dagger2的使用的更多相关文章

  1. 浅析Dagger2依赖注入实现过程

    Dragger2是Android应用开发中一个非常优秀的依赖注入框架.本文主要通过结合Google给出的MVP开发案例todo-mvp-dagger(GitHub连接地址:https://github ...

  2. Dagger2源码浅析

    dagger2是目前android端比较火的一款依赖注入框架,先来看下基本的用法吧: 首先提供module,类似于工厂: @Module public class ApiServiceModule { ...

  3. 轻松学,浅析依赖倒置(DIP)、控制反转(IOC)和依赖注入(DI) 依赖注入和控制反转的理解,写的太好了。

    轻松学,浅析依赖倒置(DIP).控制反转(IOC)和依赖注入(DI) 2017年07月13日 22:04:39 frank909 阅读数:14269更多 所属专栏: Java 反射基础知识与实战   ...

  4. SQL Server on Linux 理由浅析

    SQL Server on Linux 理由浅析 今天的爆炸性新闻<SQL Server on Linux>基本上在各大科技媒体上刷屏了 大家看到这个新闻都觉得非常震精,而美股,今天微软开 ...

  5. 【深入浅出jQuery】源码浅析--整体架构

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  6. 高性能IO模型浅析

    高性能IO模型浅析 服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型. (2)同步非阻塞IO(Non-blocking  ...

  7. netty5 HTTP协议栈浅析与实践

      一.说在前面的话 前段时间,工作上需要做一个针对视频质量的统计分析系统,各端(PC端.移动端和 WEB端)将视频质量数据放在一个 HTTP 请求中上报到服务器,服务器对数据进行解析.分拣后从不同的 ...

  8. Jvm 内存浅析 及 GC个人学习总结

    从诞生至今,20多年过去,Java至今仍是使用最为广泛的语言.这仰赖于Java提供的各种技术和特性,让开发人员能优雅的编写高效的程序.今天我们就来说说Java的一项基本但非常重要的技术内存管理 了解C ...

  9. 从源码浅析MVC的MvcRouteHandler、MvcHandler和MvcHttpHandler

    熟悉WebForm开发的朋友一定都知道,Page类必须实现一个接口,就是IHttpHandler.HttpHandler是一个HTTP请求的真正处理中心,在HttpHandler容器中,ASP.NET ...

随机推荐

  1. vue之自定义指令directive

    <template> <div> <input v-model="dir1" v-my-directive1="dir1"/> ...

  2. Web API接口设计经验总结

    在Web API接口的开发过程中,我们可能会碰到各种各样的问题,我在前面两篇随笔<Web API应用架构在Winform混合框架中的应用(1)>.<Web API应用架构在Winfo ...

  3. .Net实现拉勾网爬虫

    前几天看到一个.NET Core写成的爬虫,有些莫名的小兴奋,之前一直用集搜客去爬拉勾网的招聘信息,这个傻瓜化工具相当于用HTML模板页去标记DOM节点,然后在浏览器窗口上模拟人的浏览行为同时跟踪节点 ...

  4. 孙鑫MFC学习笔记18:ActiveX

    18 1.容器和服务器程序 2.InvalidateControl重绘控件 3. 4.GetBackColor获取背景色 5.GetForeColor获取前景色 6.TranslateColor进行颜 ...

  5. 第 27 章 CSS 传统布局[下]

    学习要点: 1.定位布局 2.box-sizing 3.resize 主讲教师:李炎恢 本章主要探讨 HTML5 中 CSS 早期所使用的传统布局,很多情况下,这些布局方式还是非常有用的. 一.定位布 ...

  6. PMP47个过程的ITO

  7. C# Unicode编码

    为了避免在浏览器中传输数据的时候出现中文乱码,我们可以将内容进行URL编码,当然也可以将内容进行UNICODE编码.将汉字进行UNICODE编码,如:"王"编码后就成了" ...

  8. linux下使用taskset设置进程cpu绑定不起作用

    自从大规模使用了虚拟化之后,大流量时soft interrupt在某个cpu很高就是个严重的问题,最近一有时间就研究这个问题,如果网卡本身不支持多队列的话,有没有办法缓解这个问题. 一开始使用rps, ...

  9. 控制器层(Controllers)

    本章译者:@freewind 业务逻辑代码通常位于模型(model)层.客户端(比如浏览器)无法直接调用其中的代码,所以模型对象提供的功能,必须作为资源以URI方式暴露给外部. 客户端使用HTTP协议 ...

  10. freeradius 安装出错的解决办法

    sudo apt-get install freeradius-mysql Selecting previously unselected package freeradius-mysql. (Rea ...