关于Dagger 2 的使用方式

什么是Dagger2

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

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

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

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

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

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

举个栗子?

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

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

 1 public class User {
 2     private String name;
 3
 4     public String getName() {
 5         return name;
 6     }
 7
 8     public void setName(String name) {
 9         this.name = name;
10     }
11 }

在Activity中对其操作

1 private void initData() {
2
3         User user = new User();
4
5         user.setName("测试");
6     }

以上是最普通的用法

接下来我们来看Dagger2的用法

我们先来配置一下Dagger2

首先在项目的 build.gradle:

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

然后是APP的 build.gradle

 1 apply plugin: ‘com.android.application‘
 2 apply plugin: ‘com.neenbedankt.android-apt‘
 3 apply plugin: ‘me.tatarka.retrolambda‘
 4 android {
 5     compileSdkVersion 23
 6     buildToolsVersion "23.0.1"
 7
 8     defaultConfig {
 9         applicationId "jiao.com.jiaoproject"
10         minSdkVersion 15
11         targetSdkVersion 23
12         versionCode 1
13         versionName "1.0"
14     }
15     buildTypes {
16         release {
17             minifyEnabled false
18             proguardFiles getDefaultProguardFile(‘proguard-android.txt‘), ‘proguard-rules.pro‘
19         }
20     }
21
22     compileOptions {
23         sourceCompatibility JavaVersion.VERSION_1_8
24     }
25
26 }
27
28 dependencies {
29     compile fileTree(dir: ‘libs‘, include: [‘*.jar‘])
30     testCompile ‘junit:junit:4.12‘
31     compile ‘com.android.support:appcompat-v7:23.3.0‘
32     compile ‘com.android.support:design:23.3.0‘
33     apt ‘com.google.dagger:dagger-compiler:2.2‘
34     provided ‘org.glassfish:javax.annotation:10.0-b28‘
35     compile ‘com.google.dagger:dagger:2.2‘
36     compile ‘com.jakewharton:butterknife:7.0.1‘
37     compile ‘com.squareup.okhttp3:logging-interceptor:3.3.0‘
38 }

首先

 1 public class User {
 2     private String name;
 3
 4     @Inject
 5     public User() {
 6     }
 7
 8     public String getName() {
 9         return name;
10     }
11
12     public void setName(String name) {
13         this.name = name;
14     }
15 }

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

接着我们看怎么使用

1     @Inject
2     User user;
3
4     private void initData() {
5
6         user.setName("测试");
7     }

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

1 @Component
2 public interface ActivityComponent {
3
4     void inject(MainActivity MainActivity);
5 }

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

1  @Inject
2     User user;
3
4     private void initData() {
5         DaggerActivityComponent.builder().build().inject(this);
6         user.setName("测试");
7     }

这时候发现我们的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中;

 1 @Module
 2 public class ActivityMoudle {
 3
 4     @Provides
 5     @Singleton
 6     OkHttpClient provideOkHttpClient() {
 7         HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
 8         loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
 9
10         Interceptor apikey = chain -> chain.proceed(chain.request().newBuilder()
11                 .addHeader("apikey", Constants.Api_Key).build());
12
13         OkHttpClient okHttpClient = new OkHttpClient.Builder()
14                 .readTimeout(Constants.HTTP_CONNECT_TIMEOUT, TimeUnit.MILLISECONDS)
15                 .connectTimeout(Constants.HTTP_CONNECT_TIMEOUT, TimeUnit.MILLISECONDS)
16                 .addInterceptor(apikey)
17                 .addInterceptor(loggingInterceptor)
18                 .build();
19
20         return okHttpClient;
21     }
22
23 }

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

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

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

1 @Singleton
2 @Component(modules = ActivityMoudle.class)
3 public interface ActivityComponent {
4
5     void inject(MainActivity MainActivity);
6 }

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

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

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

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

1  @Inject
2  OkHttpClient okHttpClient;

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

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

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

时间: 2024-10-08 16:01:38

关于Dagger 2 的使用方式的相关文章

依赖注入利器 - Dagger ?

概述 声明需要注入的对象 如何实例化出依赖 Module的使用 Component的使用 Dagger的进阶使用 Components之间的关系 dependencies Subcomponents Scopes Singlton 自定义Scope scope的作用 Lazy注入 Provider注入 Qualifiers注入 编译时验证 小结 概述 在开发过程中,为了实现解耦,我们经常使用依赖注入,常见的依赖注入方式有: 构造方法注入:在构造方法中把依赖作为参数传递进去 setter方法注入:

Dagger2 使用正确姿势。

Dagger2 使用正确姿势. 上一篇文章<Dagger2 这次入门就不用放弃了>中介绍了Dagger2的一些显浅的使用方式,我觉得是非常适合入门Dagger2的傻瓜式讲解,后来发现有些内容讲的不够仔细,有些细节没有详细解释清楚.参考了以下三篇文章后,对之前的内容进行一些补充. Android:dagger2让你爱不释手-基础依赖注入框架篇 Android:dagger2让你爱不释手-重点概念讲解.融合篇 Android:dagger2让你爱不释手-终结篇 以上这三篇文章对于Dagger2的思

Dagger 2从浅到深(七)

在使用Dagger 2开发时,一般都是在Application中生成一个AppComponent,然后其他的功能模块的Component依赖于AppComponent,作为AppComponent的子组件.可是,对于将自组建添加到父组件有两种方式: 通过@Component的dependencies属性依赖父组件 @Component(modules = OrangeModule.class, dependencies = FruitComponent.class) public interfa

Dagger 2从浅到深(六)

之前用到的,都是基于单个实例的依赖注入.强大的Dagger也支持多个元素的依赖注入,将注入的元素聚合到Set或者Map中,以便应用程序代码可以注入Set/Map,而不依赖于单独的绑定. 多个元素绑定并注入到Set 普通Set注入 将多个元素注入到Set中,不仅支持单个元素注入到Set中,同时支持子Set<T>注入到Set中. 将单个元素注入到Set: @Module() public class FruitModule { @Provides @IntoSet public BananaBea

dagger2系列之依赖方式

本篇是实战文章,从代码的角度分析这两种方式.本文参考自下列文章: http://www.jianshu.com/p/1d42d2e6f4a5 http://www.jianshu.com/p/94d47da32656 一般在项目中我们需要全局使用app或者其他,这个时候就需要有一个全局的Component作为桥梁,提供给使用方使用.一个Component可以依赖一个或多个Component,并拿到被依赖Component 暴露 出来的实例. <一>依赖关系 全局提供App实例类.上下文Cont

Dagger——Android上的依赖注入框架

* 你也可以去Github查看这片文章 简介 在开发程序的时候,会用到各种对象,很多对象在使用之前都需要进行初始化.例如你要操作一个SharedPreference,你需要调用getSharedPreferences(String name,int mode)来获取一个对象,然后才能使用它.而如果这个对象会在多个Activity中被使用,你就需要在每个使用的场景中都写下同样的代码.这不仅麻烦,而且增加了出错的可能.dagger的用途就是:让你不需要初始化对象.换句话说,任何对象声明完了就能直接用

Android Dagger依赖注入框架浅析

今天接触了Dagger这套android的依赖注入框架(DI框架),感觉跟Spring 的IOC差不多吧.这个框架它的好处是它没有采用反射技术(Spring是用反射的),而是用预编译技术,因为基于反射的DI非常地耗用资源(空间,时间) 由于现在开发都是用Android Studio了,所以我这里大概讲下配置Dagger框架的开发环境,需要怎么做. (由于Android Studio中用Gradle,所以跟传统我们用Eclipse配置的话,直接导入jar包,有点不一样.) 在开始看我的博文前,希望

在Eclipse中搭建Dagger和Dagger2使用环境

眼下Dagger有两个版本号,一个是square的Dagger1.x,另外一个是由google主导与squre联合开发的Dagger2. 本文介绍一下在Eclipse中搭建Dagger和Dagger2使用环境.样例採用的均为Dagger和Dagger2官方提供的 "咖啡"案例(Dagger1.x的案例位置在example/simple目录下.Dagger2的案例位置在example/simple目录下). Dagger1.X: 1. 首先下载Dagger1.x的相关内容. jar文件能

Android依赖注入Dagger的使用和源码解析(上篇)

一.基本概念 依赖注入(DI)和控制反转(IOC): 依赖注入是从应用程序的角度在描述,可以把依赖注入描述完整点:应用程序依赖容器创建并注入它所需要的外部资源:而控制反转是从容器的角度在描述,描述完整点:容器控制应用程序,由容器反向的向应用程序注入应用程序所需要的外部资源. 使用依赖注入可以带来以下好处: 依赖的注入和配置独立于组件之外. 因为对象是在一个独立.不耦合的地方初始化,所以当注入抽象方法的时候,我们只需要修改对象的实现方法,而不用大改代码库. 依赖可以注入到一个组件中:我们可以注入这