在之前的几篇文章中,已经了解了Dagger为何物, 如何用,使用中可能出现的问题。其中在使用环节只是简单介绍了使用@Inject注解添加依赖注入。但是@Inject有一个先天性缺陷–对于第三方jar包中的类,我们无法在其构造器中添加@Inject注解

例如我们在使用OkHttp发送网络请求的时候,经常会使用OkHttpClient类。

OkHttpClient okHttpClient;@Override
public void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 主动初始化OkHttpClient对象okHttpClient = new OkHttpClient();
}

但是如果我们要使用Dagger的@Inject依赖注入OkHttpClient对象就没有办法了, 因为okhttp是以依赖包的方式被导入到项目,我们无法修改其中的代码。如果是这种情况,就要使用接下来将要介绍的@Module注解

@Module

用Module标注的类是专门用来提供依赖的,不同于@Inject需要在构造函数上标记才能提供依赖,@Module可以标记任何类提供依赖。 可以将其看成是一个简易的工厂类, 具体使用步骤如下(以使用OkHttp为例):

一、 创建类并使用@Module注解,并添加被依赖类的工厂方法,如下所示

@Module
public class UserModule {@ProvidesOkHttpClient provideOkHttpClient() {OkHttpClient okHttpClient = new OkHttpClient.Builder().build();return okHttpClient;}
}

细心的童鞋已经发现了在provideOkHttpClient()方法上添加了一个@Provide的注解,这是什么鬼?

用@Provide来标注一个方法,该方法可以在需要提供依赖时被调用。当Dagger实例化某一个被依赖类时,会到Module 类中查找符合以下两个条件的方法来构造示例
  1. 方法被@Provide注解
  2. 方法的返回类型恰好是所需要的被依赖类类型

二、@Module类写好了之后,需要将其与Component建立关联,只有这样Component(注射器)才知道去哪里构造具体的实例对象

@Component(modules = UserModule.class)
public interface UserComponent {void bind(MainActivity mainActivity);
}

可以看到在@Component注解中,添加了modules参数并指向我们创建的@Module类 UserModule

三、在MainActivity中对声明的OkHttpClient对象添加@Inject注解

没有错,还是@Inject注解。Dagger在初始化被@Inject注解的对象的时候会按照如下步骤去实例化:

  1. 在Component中的Module中查找是否存在创建该类的方法,并被@Provide注解
  2. 若存在创建类方法,查看该方法是否存在参数
    1. 若存在,则从步骤1开始依次初始化每个参数(有点递归的赶脚)
    2. 若不存在,则直接初始化该类实例,一次依赖注入到此结束
  3. 若在所有的Module中都不存在创建类方法,则查找Inject注解的构造函数,具体详情见Dagger2 初体验

同使用@Inject时一样,如果在一个Module类中存在多个返回类型一样的方法,那Dagger会如何选择工厂方法并返回实例对象呢?

我们通过一个使用User的简单demo来实践一下,首先在UserModule中添加如下两个方法

@ProvidesUser getUserByAge() {return new User(10);}@ProvidesUser getUserByName() {return new User("DANNY");}

然后编译工程,同样会发现编译报错,log如下图所示


从log中可以看出,报错原因是以为User被多次绑定,导致编译不过。那么这种情况就要使用一种限定符告诉Dagger具体该使用Module中的哪一种工厂方法来实例化对象。 而这种限定符就@Qualifier

@Qualifier

@Qualifier 英文含义限定词,它的作用和函数的重载很像。它告诉Dagger依赖需求方 创建数据的时候使用哪个依赖提供方。 更深入一点就是使用@Qualifier我们可以自定义注解,通过自定义注解可以在Module类中区分开不同情况该使用哪一个工厂方法创建被依赖对象

具体使用步骤如下

一、使用@Qualifier创建自定义注解类

创建两个接口,分别叫UserAge和UserName,如下所示

@Qualifier
public @interface UserAge {
}
@Qualifier
public @interface UserName {
}

通过这种方式,我们就自定义了两种注解,分别为@UserAge和@UserName
注意:在interface之前也有一个@符号

二、在Module类中,分别使用自定义注解@UserAge和@UserName注解相应的工厂方法

@Provides@UserAgeUser getUserByAge() {return new User(10);}@Provides@UserNameUser getUserByName() {return new User("DANNY");}

可以看到getUserByAge和getUserByName方法除了之前的@Provide注解之外,又重新被添加了@UserAge和@UserName的注解,通过这种方式就讲这两个方法进行了区分

三、在被依赖对象的声明处,使用自定义注解标识相应的变量

在MainActivity中,分别声明user1和user2,并使用不同的自定义注解标识,如下所示:

@Inject@UserNameUser user1;@Inject@UserAgeUser user2;

重新编译,此时编译可以成功。 通过这种方式,Dagger已经知道当初始化user1和user2时分别该使用的工厂方法。最后通过将两个User的age和name显示到两个TextView上验证一下是否正确

textView = ((TextView) findViewById(R.id.tv1));textView2 = ((TextView) findViewById(R.id.tv2));textView.setText("user1 name is " + user1.getName());textView2.setText("user2 age is " + user2.getAge());

运行后,显示如下:

最后还有一个问题,如果在MainActivity中,除了user1和user2之外,还有一个user3,但是user3并没有被自定义注解标识,那会怎么样呢?

@Inject@UserNameUser user1;@Inject@UserAgeUser user2;@InjectUser user3;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);DaggerUserComponent.builder().build().bind(this);Log.e("DANNY", "user3 is " + user3.getName());textView = ((TextView) findViewById(R.id.tv1));textView2 = ((TextView) findViewById(R.id.tv2));textView.setText("user1 name is " + user1.getName());textView2.setText("user2 age is " + user2.getAge());}

可以看到user3并没有被自定义注解标识,那在onCreate方法中打印出的会是什么呢? 为了demo更加完善,将之前的User的代码也贴出来

public class User {private String name;private int age;public User() {Log.e("DANNY", "default construction called");}@Injectpublic User(Vip vip) {Log.e("DANNY", "construction with vip param called");}@Injectpublic void init2() {Log.e("DANNY", "init2 is called");}@Injectpublic void init() {Log.e("DANNY", "init is called");}public User(String name) {this.name = name;}public User(int age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}
}

在User中只有一个带Vip参数的构造器添加了@Inject注解。 最后运行一下程序,看一下打印的log如下:

通过log可以看出,user1和user2分别是调用Module中的getUserByName和getUserByAge方法获取的。 而user3并没有被自定义注解标识,则会调用被@Inject注解的构造器进行初始化(注意:如果此时在User中并没有被@Inject标识的构造器,则编译还是会报错T_T)

Dagger2 进阶相关推荐

  1. google四件套之Dagger2

    前言 网上都说Dagger2是比较难上手的,我在看了大量资料和使用时也遇到了很多不懂或者模糊的知识点,而且大部分博客资料都比较古老.突然有那么一瞬间,突然明白了所以然,故总结了4篇文章.话说在java ...

  2. Android 依赖注入框架 Dagger2使用

    前言 Dagger 2这个匕首确实很难上手,上手后又比较难瞬间掌握,可以这么说,刚开始使用就是用来尝(zhuang)鲜(X)的,但相信随着使用的加深,会不断体会到它对于整个项目架构的极强辅助作用,能使 ...

  3. 【Android 进阶】Dagger2 系列:入门案例一

    欢迎关注我的微信公众号,不只是原创技术分享,更多的是生活的思考和总结. 介绍 A fast dependency injector for Android and Java. 一个在 Android ...

  4. Dagger2 知识梳理(1) Dagger2 依赖注入的两种方式

    一.资料推荐 最近这几天一直在看有关Dagger2有关的文章,感觉就是这东西真难用.真难懂,数次想要放弃,还好有网上大神的教程帮助,模模糊糊总算能把基本的几个概念跑通了. 这里首先推荐 牛晓伟 的下面 ...

  5. 【开源推荐】进阶实战,从一款音乐播放器开始

    0.前言 前面有同学问我,想要做一个Android 实战项目,问我有没有好的开源项目可以参考和练习? 想想自己以前也是,当项目没有什么新任务的时候,想着自己写一个实战项目来来练练手,那拿什么项目来练手 ...

  6. 临近2022年末: Android 开发者的出路在哪?转行还是进阶?

    你可能知道 Android 的近况,大体上现在移动开发已经不像以前那么活跃了,完全没有了几年安卓开发的那种火热势头. 与此同时,有很多发言说 Android 的开发冷却了,不行了,没有前途了 那么到底 ...

  7. 《Android高级进阶》读书笔记

    <Android高级进阶>是据我所知的市面上唯一一本技术工具书,比较的高大全,作者的目的是为了对全领域有个初步的概念 No1: 在Android系统中,拥有事件传递处理能力的类有以下三种 ...

  8. Android进阶三部曲 第一部《Android进阶之光》已出版(内含勘误)

    独立博客版本请点击这里 勘误帖请点击这里 源码地址:https://github.com/henrymorgen/android-advanced-light 进阶三部曲第二部:http://liuw ...

  9. 寒冬之下,我的Android路要怎么走?怎么学?怎么进阶?

    前言 很多做 android 开发的同学都想多快好省,现实是真的是这样吗,借着前人的经验,我们的目标可以更加清晰,可以计划划分阶段去学习,但是学习的路是不会变的,别人会遇到什么我们也会遇到什么,别人躺 ...

最新文章

  1. 大开源时代,“仁慈的独裁者”管理模式还走得通吗?
  2. 理解Hinted Handoff
  3. 33 个 JavaScript 核心概念系列(三): 显式 (名义) 与 隐式 (鸭子)类型转换
  4. 为何我通过 Calendar1.SelectedDate.DayOfWeek.ToString() 获取的“星期”总是英文的???...
  5. 数据中心操作运营贴士:确保生命安全
  6. void类型和void *的用法
  7. MVC Controller与ActionResult的返回值
  8. Nodejs 中的包、npm 、第三方模块、 package.json 以及 cnpm
  9. OpenHarmony移植案例:如何适配服务启动引导部件bootstrap_lite
  10. Netty如何解决粘包拆包?(二)
  11. Linux下C语言编程入门-8关于计时器
  12. 做自己最好的生活大师
  13. PHP程序员必看书籍
  14. 看完315晚会,我们的数据隐私谁来保护?
  15. OneNote for windows10 鼠标点击没反应
  16. 【C++札记】类的分离式写法
  17. 关于720vr 全景平台 全景图片制作系统 仿720云需要注意的坑 诚意贴
  18. 如何保护您的数据免遭未经授权的访问
  19. 回顾腾讯电商路:马化腾之痛可否疗愈?
  20. mysql最近24小时数据_mysql中如何查询最近24小时、top n查询

热门文章

  1. mac新版迅雷,如何取消开机启动?
  2. Hystrix熔断器简介
  3. Python必学的4个实战项目,拿走不谢
  4. 华工的计算机专业硕士就业前景,这所热门地区的985就业率排名第一!不想了解下吗?...
  5. 《Linux C编程从入门到精通》——1.4 Linux的常用命令
  6. 2022年第十四届“华中杯”大学生数学建模挑战赛
  7. 2019-09-03 电感的自感,反电动势方向
  8. 知乎zse-96算法-js补环境方案
  9. 基于C#的Modbus的(NModbus)研究(DTS686电表)——实现TCP通信连接(二)
  10. MySQL - 04.数据控制语言(Data Control Language,DCL)