从 Dagger 到 Hilt,谷歌为何执着于让我们用依赖注入?

来源 | 扔物线

责编 | Carol

文章开始之前,首先来看个视频:


开始

说到依赖注入,做 Android 的人都会想到一个库:Dagger;说到 Dagger,大家的反应普遍是一套三连:牛逼、高端、我才不用。

又牛逼又高端,为什么不用?因为太难了。是吧?又难学又难用。大多数的人在学习 Dagger 的路上就被直接劝退了,剩下的这一小撮人最终排除万难,学会并且用上了 Dagger,但多半都是用着用着就掉进了自己亲手用 Dagger 搭建的迷宫里,怎么也绕不清楚,而且越陷越深,就这么成年累月地被它折磨。

有人可能会说:难用就别用呗?拆出来啊。

拆?哼哼。你对 Dagger 一无所知。

而就在上个月,Android 团队又在 Jetpack 里面又增加了一个新的依赖注入库:Hilt。这个 Hilt 是专门针对于 Android 平台的依赖注入库,它是基于 Dagger 的。

啊?基于……Dagger?这次到底是真正的神器到来,还是又一个大坑?


依赖注入是什么?

Dagger 的名字取自有向无环图 DAG (directed acyclic graph):

因为程序里的依赖关系拼接起来就是一个或者多个有向无环图:

DAG-er,Dagger,取了个谐音,Dagger 是匕首的意思。而这次的 Hilt 是刀柄的意思,匕首很难用是吧?来,给你个柄。

说得很好听,到底有没有那么好用啊?这是个复杂的问题,且听我慢慢道来~

依赖注入有什么用

Hilt 好不好用,我们先来看看它是个什么。它是个用注解来进行配置的依赖注入库。注解是它的写法,首先它是个依赖注入库,对吧?什么是依赖注入?一个类里有两个变量,这两个变量就是它的依赖:

要初始化一个依赖,有两种方法:第一,你这个类自己初始化:

第二,让外部帮你初始化。

其中这第二种,让外部帮你初始化你的依赖,就叫依赖注入。关键在于初始化是谁做的,至于最后一步是你把结果拿过来,还是说你连拿都不用拿,最后一步的赋值工作也让外部来帮你做了,这都不重要,只要初始化工作是外部做的,就都叫依赖注入。

所以 Factory 的使用是依赖注入吗?

是的。

Builder?

也是。

带参数的构造函数?

也是!

这些都属于由外部来提供依赖的初始化,所以都是依赖注入,并不是非要像 Dagger 那样使用注解的像魔法一样的才叫依赖注入。也就是说,其实我们每个人都已经在使用依赖注入了。虽然很多人在面对 Dagger 的时候会问「依赖注入到底有什么用」,但其实 Dagger 并不是提供了依赖注入的能力,而是为依赖注入提供了一种更简单的方式。依赖注入本来就是有用的,这个问题不想明白,不管是 Dagger 还是现在的 Hilt,你都用不好。

Dagger 让我们可以用注解的方式来配置依赖关系,让依赖注入变得更方便。不过由于功能复杂,导致它的上手非常困难;再加上刚才我说的,很多人对于依赖注入的作用以及 Dagger 的定位都没搞清楚,这两个原因加起来,就导致很多人还没学会 Dagger 就把它弃了,让 Dagger 成为 Android 史上最受冷落的优质库。这样的结果不论是对 Dagger 还是对我们,都是很可惜的。

而 Hilt 的出现,就直接解决了 Dagger 太复杂的这个问题。

Hilt 怎么帮助我们进行依赖注入

Hilt 是 Google 专门针对 Android 平台做的一个依赖注入库。它不是从里到外全新开发的,而是基于 Dagger 做的,它的下层还是 Dagger。

为什么不直接去优化改进 Dagger,而要基于它做一个新库呢?因为 Hilt 做的事其实也并不是对 Dagger 进行优化,而是场景化:针对 Android 开发制定了一系列的规则,通过这些规则大大简化了这套工具的使用。例如在 Dagger 里,你要对某个类的依赖进行注入,你需要手动获取依赖图和执行注入依赖操作:

而在 Hilt 里,注入会自动完成:

因为 Hilt 会自动找到 Android 的系统组件里面那些最佳的初始化位置——比如 Activity 的 onCreate() ——然后在这些位置注入依赖。所以,为什么不是去优化 Dagger,而是做了个新库?因为 Hilt 本身并不是一种优化,而是场景化,或者说,它是一种针对场景的优化。总之,它是不通用的,只能给 Android 用,所以不能放在 Dagger 里。

有点明白了吧?

那它具体怎么用呢?大概是这样的:

我们程序里有些对象是全局共享的,比如线程池,或者 Retrofit 对象,这种东西我们通常会把它放在 Application 对象里,或者做成单例的:

而如果用 Hilt,你也可以把它做成自动注入的依赖:

还有些对象是局部共享的,比如某个 Activity 会把一些显示用的数据共享给它内部的一些 View 和 Fragment。这一类情况我们的做法通常是获取外部 Activity 对象然后强转,再去拿它内部的对象:

而如果用 Hilt,你可以把这个对象直接声明出来,让它自动注入:

这不只是一个「美观」的差别,依赖注入可以让你的程序更加灵活,比如如果你的 View 可以在多个不同的 Activity 里显示,那你在 View 里面要怎么强转?你要转成谁?

很麻烦,是吧?而如果用依赖注入,这些就都是自动的。

除了共享的对象,不共享的也可以用依赖注入的方式来进行初始化,因为依赖注入的作用除了对共享对象提供一致性支持,也可以让我们在创建任何对象的时候省一些思考和力气:

@Inject newUser: User

总之,如果一个组件可能会被被共享,或者不会被共享但可能会在多处使用,你都可以使用 Hilt 来把它配置成依赖注入的加载方式。

加载的方式可以选择直接调用构造函数:

或者指定子类或实现类:

或者干脆给出具体的代码:

加载的作用域可以选择默认的每次都初始化,也可以设置成全局单例的:

也可以设置成针对任何 Activity、Fragment、View 或者 ViewModel 的局部共享:

简单又强大,好用又灵活。具体的写法你可以去看文档,或者过段时间我会有一次公开课,到时候也会提前通知大家。

到这里有的人可能会分个叉可能会想:诶 ButterKnife 或者现在 Jetpack 推出的 ViewBinding 它们提供的功能,Hilt 提供了吗?因为如果提供了,我在用了 Hilt 之后,不就可以把 ButterKnife 和 ViewBinding 扔掉了?

不好意思,Hilt 不提供它们的功能。Hilt 和 Dagger 虽然用法和 ButterKnife 很像,都是给变量加注解,然后变量会自动赋值,但它们的功能定位是不一样的:Hilt 和 Dagger 是做依赖注入的,而 ButterKnife 和 ViewBinding 是做视图绑定的。

这可不是个文字游戏,依赖注入和视图绑定是有本质区别的:依赖注入是由外部对对象进行初始化,也就是所谓的控制翻转;而视图绑定是让变量去指向一个已经有了的 View,它的依赖依然是由依赖持有者自己决定的,这是一个本质的区别。

Dagger 为什么难用

这么看来,Hilt 还是很好用的,是吧?那有些人就又有问题了:哎,Hilt 这么好用,那Dagger 真的难用吗?到底难用在哪了?

其实说白了,Dagger 的难用主要在于这个框架太强大和灵活了,导致你要遵守很多约定才能正确使用它。比如在 Hilt 里,一个注解就能让 Activity 内部的依赖自动被注入,而 Dagger 需要手动注入;再比如在 Hilt 里如果你想让一个对象只在 Activity 内部被共享而不是全局共享,也就是一个注解能解决的问题,而在 Dagger 里面你需要先去创建一个自定义的注解。这些难吗?每个都不难的,对吧?但把它们放在一起,让你灵活搭配使用,就有点难了。

另外,Dagger 被大家普遍认为难的另一个原因刚才我也说过了:很多人连依赖注入都不太懂的。所以我再说一遍:如果一个组件可能被共享,或者可能在多处被使用,你可以使用依赖注入来初始化它。然后,在需要依赖注入的场景里,使用 Dagger 能让你的依赖注入写起来更简单。最后,Hilt 进一步简化了这个事情。先知道它是什么,再去用它。

总结

 

所以今天表面上是在介绍 Hilt,其实是对于 Hilt 以及它背后的依赖注入机制进行一个整体的讲解,希望对你可以有帮助。大家学知识和技术的时候,一定不要只关注表面,要透过表面看到里面的本质,掌握最核心的东西。

那么回到这期的标题——《从 Dagger 到 Hilt,谷歌为何执着于让我们用依赖注入》,为什么?其实谷歌并没有非要让我们使用依赖注入,而是我们本来就需要使用依赖注入,谷歌只是想提供一种更方便的方式让我们去使用依赖注入而已。Dagger 很强大,但太难学从而导致太难用;而 Hilt 彻底扫除了这个障碍,那……

要不咱给它个机会?

更多阅读推荐

  • 闲鱼的云原生故事:靠什么支撑起万亿的交易规模?

  • 野鸡大学怎么知道考生电话的?

  • 达摩院NLP团队斩获六项世界冠军背后,让AI没有难懂的语言

  • 我把这篇文章给女朋友看,她终于明白什么是「数据中台」了

  • 云交易所已成资金盘、杀猪盘重灾区,曾被寄予厚望,如今罪恶丛生

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/516672.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Directory /opt/jfrog/artifactory/var has bad permissions for user id 1030

文章目录1. 现象2. 分析定位3. 解决方案1. 现象 2. 分析定位 由于映射目录无权限导致的 3. 解决方案 ①添加--privilegedtrue ②赋予映射目录777权限 企业案例: mkdir /app/jfrog/artifactory chmod 777 /app/jfrog/artifactorydocker run --name artifactory-…

120万人同时在线考试,这么大的流量如何支撑

云栖号资讯:【点击查看更多行业资讯】 在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 三月原本是全国各地中小学生逐步开启新学期的日子,但这场突如其来的疫情使得1.8亿中小学生只能纷纷在家开启“停课…

异步懒加载和彻底懒加载

异步懒加载: 彻底懒加载 :

JFrog Container Registry 搭建Docker镜像仓库 (docker 版本)

文章目录1. 镜像拉取2. 创建容器3. 效果验证1. 镜像拉取 docker pull artifactory-jcr:latest2. 创建容器 docker run --name artifactory-jcr \ -d \ -v /app/jfrog/artifactory:/var/opt/jfrog/artifactory \ -p 8081:8081 -p 8082:8082 \ --privilegedtrue \ docker.bintr…

美国AI博士指出,自学Python到底能做什么

我见过市面上很多的 Python 讲解教程和书籍,他们大都这样讲 Python 的:先从 Python 的发展历史开始,介绍 Python 的基本语法规则,Python 的 list, dict, tuple 等数据结构,然后再介绍字符串处理和正则表达式&#xff0…

MySQL实战—更新过程

本文属于个人备忘录,主要是极客时间《MySQL实战45讲》学习笔记。 MySQL实战—更新过程 一条查询语句的执行过程一般是经过连接器、分析器、优化器、执行器等功能模块,最后到达存储引擎。那么更新语句又是如何执行? 和查询流程不同的是&…

系列文章:Kubernetes日志采集最佳实践

前言 上一期主要介绍Kubernetes日志输出的一些注意事项,日志输出最终的目的还是做统一的采集和分析。在Kubernetes中,日志采集和普通虚拟机的方式有很大不同,相对实现难度和部署代价也略大,但若使用恰当则比传统方式自动化程度更…

JFrog Container Registry 搭建Docker镜像仓库 (tar.gz 版本)

文章目录1. 下载安装包2. 解压3. 启动软件4. 防火墙5. 效果验证1. 下载安装包 https://www.jfrog.com/ 2. 解压 tar -zxvf jfrog-artifactory-jcr-7.27.10-linux.tar.gz3. 启动软件 前台启动 cd /app/artifactory-jcr-7.27.10/app/bin./artifactory.sh4. 防火墙 关闭防…

智领云荣登“中国大数据企业50强” | 2020大数据产业生态大会盛大召开 智领云斩获多项殊荣

近年来,我国大数据生态环境不断向好,产业发展维持高增长态势,大数据技术在与政府、企业核心业务的融合中,释放出了更多创新活力和应用潜能。 8月27日,2020(第五届)大数据产业生态大会在京隆重召…

性能提升约7倍!Apache Flink 与 Apache Hive 的集成

导读:随着 Flink 在流式计算的应用场景逐渐成熟和流行,如果 Flink 能同时把批量计算的应用场景处理好,就能减少用户在使用 Flink 时开发和维护的成本,并且能够丰富 Flink 的生态。SQL 是批计算中比较常用的工具,所以 Flink 针对于…

日均万亿条数据如何处理?爱奇艺实时计算平台这样做

摘要:本文由爱奇艺大数据服务负责人梁建煌分享,介绍爱奇艺如何基于 Apache Flink 技术打造实时计算平台,并通过业务应用案例分享帮助用户了解 Apache Flink 的技术特点及应用场景。提纲如下: 爱奇艺 Flink 服务现状Flink 改进实时…

进入编译器后,一个函数经历了什么?

来源 | 编程技术宇宙责编 | Carol封图 | CSDN 付费下载自视觉中国我是一个函数我是一个函数,名叫str_upper,我可以把输入的字符串从小写变成大写。不信你看,我长这样:char* str_upper(char* str, int len) {char upper[256];if (l…

docker sonarqube 7.7 sonar-scanner-4.6.2 maven 安装、搭建+实战

文章目录一、docker安装Mysql1. 映射目录2. 赋予权限3. 镜像拉取4. 运行容器5. 查看日志6. 创建数据库二、docker安装sonarqube2.1. 映射目录2.2.赋予权限2.3. 镜像拉取2.4. 运行容器2.5. 查看日志二、中文简体2.1. 版本对照2.2. download2.3. 重启容器三、规则添加3.1. 规则无…

使用CLONE TABLE方式实现同region不同可用区的MaxCompute

该文章主要针对于用户同region不同账户之间的MaxCompute数据迁移方式,属于迁移的方式可以有三种方式,一、添加MaxCompute数据源的方式进行数据迁移(该方式针对多个表配置同步节点较为繁琐);二、使用tunnel方式结合代码…

Fabric中的Transient Data与Private Data

在Hyperledger Fabric中有两个相关的概念:私有数据(Private Data)和暂态数据(Transient Data)。本文提供四个示例程序,分别对应私有数据和暂态数据的四种组合使用方式,并通过观察账本的交易以及…

窃隐私、放高利贷,输入法的骚操作真不少!

来源 | 编程技术宇宙责编 | 李雪敬封图 | CSDN 付费下载自视觉中国光说隐私泄露,人们总觉得似乎离自己很远,然而它早已像一个“地雷”,悄悄埋进了我们的生活中,不是不爆,时候未到。别认为自己只是社会中的一个小透明&a…

快速迁移 Next.js 应用到函数计算

首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传。函数计算准备计算资源&#xff…

为什么字节跳动、腾讯、阿里都在用Python??

Python 作为一种解释型技术脚本语言,越来越被认可为程序员新时代的风口语言。 无论是刚入门的程序员,还是年薪百万的 BATJ 的技术大牛都无可否认:Python的应用能力是成为一名码农大神的必要项。 而作为Python初学者来讲,最大的问题…

Need to upgrade docker package to 17.06.0+. Docker升级到最新版本

文章目录1. 现象2. 查找3. 在线卸载4. 升级docker5. 重启Docker6. 设置Docker开机自启7. 查看版本背景: 在搭建docker私有仓库的时候出现以下错误,版本太低 1. 现象 Need to upgrade docker package to 17.06.0.2. 查找 查找主机上关于Docker的软件包 …

云数据库RDS基础版的优势及适用场景

云栖号快速入门:【点击查看更多云产品快速入门】 不知道怎么入门?这里分分钟解决新手入门等基础问题,可快速完成产品配置操作! 阿里云的产品系列包括基础版、高可用版、集群版、三节点企业版,本文介绍基础版的相关信息…