为什么要使用依赖注入?直接new对象不香吗?为什么要把简单的问题复杂化?

作者:newki

为什么要使用依赖注入?直接new对象不香吗?为什么要把简单的问题复杂化?

你是不是在炫技,是不是像装13?

这还真不是,如果说我使用的Dagger2,还真是炫技,NB啊。Dagger的坑也是真的多,能在大项目中把Dagger用好,那还真是牛,但是我们现在都用Hilt了有什么可装的,使用是真的简单,都是一些场景化的东西,一些固定用法。没必要没必要。

回归正题,为什么要使用依赖注入?哪种情况下推荐使用依赖注入?就算要用依赖注入,为什么依赖注入推荐使用Hilt?

一、自动管理(灵活与解耦)

首先不是说大家写项目就一定要使用依赖注入,如果大家的项目不是大项目,总共就5、6个,10多个页面,你没必要上依赖注入框架,如果是大项目,分模块,分组件,多人协同开发的,并且可能依赖的对象很复杂,或者说套娃似的对象依赖,那么使用Hilt就非常方便。不同模块/组件的开发人员直接在他自己的组件/模块下定义好对象的提供方式,另一边直接用即可,无需关系依赖的复杂度,和实现的逻辑。

我们先看看一些复杂的嵌套依赖,比如我们来一个三层套娃的依赖:

@Singleton
class UserServer @Inject constructor(private val userDao: UserDao) {fun testUser() {YYLogUtils.w(userDao.printUser())toast(userDao.printUser())}fun getDaoContent():String{return userDao.printUser()}}

@Singleton
class UserDao @Inject constructor(private val user: UserBean) {fun printUser(): String {return user.toString()}}

data class UserBean(val name: String,val age: Int,val gender: Int,val languages: List<String>
)

其他三个类都是必须了,其实也就多了一个这个类,提供UserBean对象

@Module
@InstallIn(SingletonComponent::class)
class Demo10DIModule {@Singleton@Providesfun provideUser(): UserBean {return UserBean("newki", 18, 1, listOf("中文", "英文"))}}

使用:

@AndroidEntryPoint
class Demo10DIActivity : BaseVMActivity() {@Injectlateinit var userServer: UserServeroverride fun getLayoutIdRes(): Int = R.layout.activity_demo10_dioverride fun init() {findViewById<Button>(R.id.btn_01).click {YYLogUtils.w(userServer.toString())userServer.testUser()}}

如果不使用Hilt,自己new对象也能实现

class Demo10DIActivity : BaseVMActivity() {lateinit var userServer: UserServeroverride fun getLayoutIdRes(): Int = R.layout.activity_demo10_dioverride fun init() {//自己new三个对象userServer = UserServer(UserDao(UserBean("newki", 18, 1, listOf("中文", "英文"))))findViewById<Button>(R.id.btn_01).click {YYLogUtils.w(userServer.toString())userServer.testUser()}}

这样new出来的对象,且不说生命周期是跟随页面的,无法保持单例,我们就说如果需求变了,UseDao中需要UserBean和UserProfile2个对象了,如果你是new对象,那么就要到处修改,如果是Hilt的方式,我们就只需要修改UserDao对象的构造即可

@Singleton
class UserDao @Inject constructor(private val user: UserBean,private val profile:UserProfile) {fun printUser(): String {return user.toString()}}

以上只是举个简单例子,构建一个对象,还要构建一堆其他的对象,并且其他对象的构建同样复杂,并且必须按顺序构建,而且需要的对象的生命周期都不一样,有些生命周期可能和Activity一样,有些可能是单例,所以在构建的时候还要考虑对象声明周期,考虑对象的来源。

特别是在大型项目中很痛苦,因为项目不是一个人写的,大家协同合作开发,看别人的代码也和看天书一样,并不知道同事的对象是如何创建的,如果一个对象的构建方式发生改变,会影响整个的构建过程以及所关联的代码,牵一发而动全身。

这个时候依赖注入框架就派上用场了,我们只用专注于怎么实现功能,对象的依赖关系和生命周期,都让它来帮我们管理,一个Inject,它会按照依赖关系帮我们注入我们需要的对象,并且它会管理好每个对象的生命周期,在生命周期还没结束的情况下是不会重复new的。

所以Hilt依赖注入非常适合大项目,小项目开发者因为项目复杂度低,没遇到这些问题,所以不会理解为什么要用Hilt依赖注入,发出疑问,为什么要让简单的new对象搞这么复杂。

二、生命周期控制

这里说对象的生命周期,其实就是在一定作用域的生命周期,如果只是说单例有点太浅薄,可以说是是在一定范围内的单例。

我们直接new对象是无法控制生命周期的,除非我们使用全局单例的对象,而通过Hilt依赖注入我们可以很方便的实现对象的生命周期的控制。

比如我们普通对象的快速注入方式,直接注解Singleton就标注的是全局范围单例

@Singleton
class UserServer @Inject constructor(private val userDao: UserDao) {fun testUser() {YYLogUtils.w(userDao.printUser())toast(userDao.printUser())}fun getDaoContent():String{return userDao.printUser()}}

另一种用法是我们使用Module的方式定义依赖注入,那么使用SingletonComponent + Singleton 同样是全局范围单例的意思

@Module
@InstallIn(SingletonComponent::class)
class Demo10DIModule {@Singleton@Providesfun provideUser(): UserBean {return UserBean("newki", 18, 1, listOf("中文", "英文"))}}

如果我们想Activity内的单例,我们使用ActivityComponent + ActivityScoped 就是Activity范围的单例。

@Module
@InstallIn(ActivityComponent::class)
class Demo10DIModule {@ActivityScoped@Providesfun provideUser(): UserBean {return UserBean("newki", 18, 1, listOf("中文", "英文"))}}

以上两种都是比较常用的作用域,其他的我们还能保证Fragment内单例,View内部单例等等,用法都是同样的用法。

所以对依赖对象的生命周期控制也是Hilt很方便的一个特点,使用new对象是无法做到这一点的。

三、对比其他依赖注入

目前Android主流的也就是三种依赖注入 Dagger2 Hilt Koin。

之前比较过Koin,只能在Kotlin语言环境中使用。并且性能并不会好过Hilt。错误提示也不友好。

Dagger2不是不能用,17年18年的时候特别火,但是学习成本很高,每次创建UI个依赖注入类还得mackproject,并且错误的提示也不友好,

其实我17年就已经在使用Dagger2了,然后自己做了Demo与框架封装,后来做项目中并没有使用,一个是坑太多,一个是同事不会用,学习成本太高。也就放弃使用Dagger2了。

而Hilt其实就是Daggert2的Android场景化的实现,内部对Dagger2进行了封装,在Android开发中使用Hilt更加的简便,学习成本很低,错误提示友好。并且还对ViewModel都可以注入了哦。所以说它是专为Android开发而生。

关于注入的对象内存占用是否有优化的这一点,其实并没有文章或者官方的文档指出有内存优化这一点,仅我自己的测试来说,整个页面如果有多个注入对象和直接new对象相比,感觉注入的对象占用内存稍微少一点,不知道是不是测试的波动,我不理解,如有懂的大佬还望指点一下。

总结

总结为什么要使用Hilt。

  1. 偷懒;自动管理,多对象的自动注入,万一有修改不需要到尸山中到处趴。
  2. 单例;让对象拥有生命周期,无需我们自己手动单例创建,然后去手动注销。
  3. 解耦;不需要到处引入我一些不需要的对象,特别是组件化的项目,另一个组件只管注入,在我的组件中我只管引用。

我觉得这是我使用Hilt最吸引我的三个点,

所以说目前2022年了,依赖注入我推荐Hilt。关键使用简单,在Android的常用场景下我还做了一些 Demo, 总共就那么多固定的一些用法,之前我写过Demo覆盖Android开发大部分的使用场景, 有需要直接拿走即可,可以查看我之前的文章。

顺便说一句,这是国外程序员的必备面试技能,感觉相比国内的开发者老外的Android开发者特别喜欢使用Dagger2和Hilt,不少老项目都是用Dagger2的。

Android 学习笔录

Android 性能优化篇:https://qr18.cn/FVlo89
Android 车载篇:https://qr18.cn/F05ZCM
Android 逆向安全学习笔记:https://qr18.cn/CQ5TcL
Android Framework底层原理篇:https://qr18.cn/AQpN4J
Android 音视频篇:https://qr18.cn/Ei3VPD
Jetpack全家桶篇(内含Compose):https://qr18.cn/A0gajp
Kotlin 篇:https://qr18.cn/CdjtAF
Gradle 篇:https://qr18.cn/DzrmMB
OkHttp 源码解析笔记:https://qr18.cn/Cw0pBD
Flutter 篇:https://qr18.cn/DIvKma
Android 八大知识体:https://qr18.cn/CyxarU
Android 核心笔记:https://qr21.cn/CaZQLo
Android 往年面试题锦:https://qr18.cn/CKV8OZ
2023年最新Android 面试题集:https://qr18.cn/CgxrRy
Android 车载开发岗位面试习题:https://qr18.cn/FTlyCJ
音视频面试题锦:https://qr18.cn/AcV6Ap

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

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

相关文章

docker搭建es+kibana

docker搭建eskibana 0 安装docker 如果是mac或者windows&#xff0c;可以直接安装Docker Desktop更加便捷。 前提条件&#xff1a; Docker可以运行在Windows、Mac、CentOS、Ubuntu等操作系统上 Docker支持以下的CentOS版本&#xff1a; CentOS 7 (64-bit)CentOS 6.5 (64-bit…

前端需要理解的浏览器知识

1 浏览器架构 浏览器是多进程多线程的应用程序&#xff0c;多进程可以避免相互影响和减少连环崩溃的几率&#xff1a; 浏览器&#xff08;主&#xff09;进程&#xff1a;主要负责界⾯显示、⽤户交互、⼦进程管理、存储等功能。内部会启动多个线程分别处理不同的任务。⽹络进…

在线设计APP ui的网站,分享这7款

在数字时代&#xff0c;用户界面&#xff08;UI&#xff09;设计变得非常重要&#xff0c;因为良好的UI设计可以改善用户体验&#xff0c;增强产品吸引力。随着科学技术的发展&#xff0c;越来越多的应用在线设计网站出现&#xff0c;为设计师和团队提供了一种新的创作方式。本…

论文笔记: One Fits All:Power General Time Series Analysis by Pretrained LM

1 intro 时间序列领域预训练模型/foundation 模型的研究还不是很多 主要挑战是缺乏大量的数据来训练用于时间序列分析的基础模型——>论文利用预训练的语言模型进行通用的时间序列分析 为各种时间序列任务提供了一个统一的框架 论文还调查了为什么从语言领域预训练的Transf…

什么是软件压力测试?软件压力测试工具和流程有哪些?

软件压力测试 一、含义&#xff1a;软件压力测试是一种测试应用程序性能的方法&#xff0c;通过模拟大量用户并发访问&#xff0c;测试应用程序在压力情况下的表现和响应能力。软件压力测试的目的是发现系统潜在的问题&#xff0c;如内存泄漏、线程锁、资源泄漏等&#xff0c;…

开源软件的崛起:历史与未来

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

go学习之go的语法知识

文章目录 1.go语言开发注意事项2.golang常用的转义字符(escape char)3.golang开发常用的问题小结与提示&#xff1a; 4.go语言注释类型&#xff08;1&#xff09;.注释类型1&#xff09;行注释2&#xff09;块注释(多行注释) &#xff08;2&#xff09;使用细节&#xff1a;1&a…

2023国赛数学建模思路 - 案例:退火算法

文章目录 1 退火算法原理1.1 物理背景1.2 背后的数学模型 2 退火算法实现2.1 算法流程2.2算法实现 建模资料 ## 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 退火算法原理 1.1 物理背景 在热力学上&a…

Qt跨平台无边框窗口探索记录

一、前言 实现的效果为&#xff1a;通过黑色矩形框预操作&#xff0c;鼠标释放时更新窗口。效果图如下&#xff1a; 1.功能 1.1 已实现功能 8个方向的缩放标题栏拖动标题栏双击最大化/正常窗口窗口最小尺寸预操作框颜色与背景色互补多屏幕默认标题栏 1.2 待开发功能 拖动到…

(学习笔记-调度算法)内存页面置换算法

在了解内存页面置换算法前&#xff0c;我们得先了解 缺页异常&#xff08;缺页中断&#xff09;。 当 CPU 访问的页面不在物理内存中时&#xff0c;便会产生一个缺页中断&#xff0c;请求操作系统将缺页调入到物理内存。那它与一般的中断主要区别在于: 缺页中断在指令执行 [期…

vue项目引入svg组件全过程

文件格式 svg下方对应 .svg index.vue svg-icon 组件 <template><svg:viewBox"viewBox"xmlns"http://www.w3.org/2000/svg"xmlns:xlink"http://www.w3.org/1999/xlink"ref"svg"class"svg-icon":class"class…

Mysql 设置表字段自动赋值创建时间,以及自动更新某一个字段的更新时间

使用场景 一般表设计中记录都有创建时间以及更新时间&#xff0c;而 Mysql 也支持了这种通用的设计需求。 即&#xff1a;可以通过默认值来给时间字段自动赋值&#xff0c;在创建时的默认值就是当前时间也就是记录的创建时间。 记录更新&#xff1a;即某一记录更新时我们要更…