Hilt 入门:什么是 Hilt、依赖注入概述、Hilt 与传统 Dagger 对比
开始讲 Hilt 之前,我想先跟你聊聊“依赖注入”这回事。
很多做 Android 的同学,刚开始接触依赖注入时都会一脸懵。我当年也是。
总觉得这东西可有可无,手动 new 对象不也挺好?后来在一个中型项目里,改一个网络库的依赖,结果跑了十几个类改构造函数……改完还要调测试。那一次之后,我彻底服了。
Hilt 就是 Google 为了让我们在 Android 上更舒服地使用依赖注入而推出的“官方”方案。
说白了,它帮我们省掉了手动搭建 Dagger 的那堆模板代码,同时保留了依赖注入带来的所有好处。
依赖注入,到底是什么鬼?
依赖注入(Dependency Injection,简称 DI)不是什么高深概念。
你可以把它想象成一个“管家”。你告诉管家你需要什么(比如一个网络请求对象),管家负责找到、组装好,然后送到你手上。
你不用自己管它是怎么创建的,也不用管它依赖的其他东西(比如数据库、缓存)是怎么实例化的。
核心好处就三点:
- 解耦 – 类与类之间不再硬编码依赖关系
- 可测试 – 注入 Mock 对象替换真实依赖,单元测试变得简单
- 可复用 – 同一个依赖可以共享,不用重复创建
在 Android 中,依赖注入有两种主流实现:Dagger 和 Hilt。
Dagger 是 Square 开源的,后来 Google 接手并优化。但 Dagger 的配置非常繁琐,你需要手动写 Component、Module、Builder……我见过不少项目因为 Dagger 配置太复杂,最后直接弃坑的。
Hilt 是 Google 在 2020 年推出的“Dagger for Android”,它在 Dagger 基础上封装了一套标准组件,让你几乎不用手写那些模板代码。
Hilt 是什么?为什么用它?
Hilt 是一个专为 Android 设计的依赖注入框架。
它基于 Dagger 构建,但暴露给开发者的 API 更加简洁。你只要加几个注解,框架就会自动帮你生成依赖图。
我个人的习惯: 只要项目达到“需要网络请求 + 数据库 + 仓库层”的规模,我就会上 Hilt。前期花半小时配置好,后期改依赖就像改配置文件一样轻松。
Hilt 的核心理念:Android 组件自动注入。
比如 Activity、Fragment、Service、BroadcastReceiver 这些组件,Hilt 可以自动把依赖注入进去,你不需要手动获取 Component。
Hilt vs Dagger:一把梭还是轻装上阵?
很多人在选 DI 框架时会纠结:直接用 Dagger,还是上 Hilt?
我先给你看个对比表,一目了然。
| 对比维度 | Dagger | Hilt |
|---|---|---|
| 配置复杂度 | 需要手动编写 Component、Module、Builder | 自动生成标准 Component(如 SingletonComponent) |
| Android 集成 | 需要手动处理生命周期和作用域 | 内置 Android 组件生命周期感知 |
| 学习曲线 | 陡峭,需要理解 Component 图、作用域链 | 平缓,注解驱动,上手快 |
| 模板代码量 | 较多,每个 Feature 都要写 Dagger 相关代码 | 极少,大部分由注解和 Hilt 插件自动生成 |
| 官方支持 | 社区维护(虽然 Google 也参与) | Google 官方维护,与 Jetpack 深度整合 |
| 灵活性 | 极高,可以自定义任何作用域、组件关系 | 较高,但受限于预定义的组件层次 |
看到这里你可能会问:那 Dagger 是不是该淘汰了?
也不完全是。如果你的项目极端复杂,需要自定义组件层级(比如跨模块的复杂作用域),Dagger 仍然有优势。但 90% 的 Android 项目,Hilt 就够用了。
我曾经在一个 20 个模块的项目里使用 Hilt,所有跨模块的依赖都通过 Hilt 的标准组件解决,没有任何需要自定义 Component 的地方。如果你也是这种“标准 Android 项目”,用 Hilt 准没错。
代码实战:第一个 Hilt 注入
说再多不如跑个例子。我们来写一个最简单的 Hilt 注入。
首先,在 build.gradle(项目级) 添加 Hilt 插件依赖:
// 项目级 build.gradle
buildscript {
dependencies {
classpath 'com.google.dagger:hilt-android-gradle-plugin:2.48'
}
}
然后,在 build.gradle(模块级) 应用插件并添加依赖:
// 模块级 build.gradle
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'com.google.dagger.hilt.android'
}
dependencies {
implementation 'com.google.dagger:hilt-android:2.48'
kapt 'com.google.dagger:hilt-compiler:2.48'
}
接着,创建一个 Application 类,并用 @HiltAndroidApp 注解:
@HiltAndroidApp
class MyApplication : Application() {}
现在,我们创建一个需要注入的类,并用 @Inject constructor:
class UserRepository @Inject constructor() {
fun getUser(): String = "Hello Hilt!"
}
最后,在 Activity 中使用 @AndroidEntryPoint 和 @Inject 注入它:
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject lateinit var userRepository: UserRepository
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
println(userRepository.getUser()) // 输出 "Hello Hilt!"
}
}
嗯,就这么简单。不加 Hilt 之前,你需要在 onCreate 里手动 new 一个 UserRepository,如果 UserRepository 又依赖别的类,你还得把所有依赖链都手动初始化一遍。Hilt 帮你把这一切自动化了。
Hilt 依赖注入核心架构图
为了让理解更直观,我画了一张图,展示 Hilt 注入的整体流程:
我给你一个避坑指南: 注意 @HiltAndroidApp 必须在 Application 类上添加,否则 Hilt 不会生成任何 Component。我曾经在写测试 Demo 时忘了加,结果编译通过但运行时报 “Hilt Application is missing”,排查了半天才发现是这个小疏忽。
好,这就是 Hilt 入门的全部核心内容。
你可能会觉得现在还比较抽象,别急,在第 2 章我们会深入 Hilt 的 Module 和作用域,到时候我会结合具体的渲染性能案例来讲解依赖注入到底如何影响 UI 流畅度。