Hilt 简介与编译时处理概述
说起依赖注入(DI),大家可能都听过 Dagger。但 Dagger 的学习曲线确实有点陡,配置起来也麻烦。Hilt 就是 Google 在 Dagger 基础上封装的「开箱即用」方案。说白了,它帮你省掉了手动写 Component、Module 绑定这些模板代码 —— 你只要加几个注解,框架就帮你自动生成 Dagger 组件。
我最早接触 Hilt 是在一个中型电商项目里,当时团队想统一 DI 方案,又不想让新手被 Dagger 吓跑。用了 Hilt 之后,新人上手快了不少,但编译报错还是让人头疼。嗯,这就是咱们这门课的核心 —— 搞懂 Hilt 在编译时干了什么,以及怎么诊断那些「额外请求」导致的编译问题。
Hilt 到底在编译时做了什么?
一句话概括:Hilt 是一个基于 Dagger 的注解处理器 + 代码生成器。它在编译期间扫描你写的 @HiltAndroidApp、@AndroidEntryPoint、@Module、@Provides 等注解,然后生成对应的 Dagger 组件和工厂类。
举个例子:你写了一个 @AndroidEntryPoint 注解在 Activity 上,Hilt 就会生成一个 Hilt_YourActivity 基类,并帮你创建 ApplicationComponent、ActivityComponent 等组件树。
- 注解扫描:收集所有 Hilt 相关注解(入口、模块、绑定)。
- 验证:检查配置有没有遗漏,比如 @HiltAndroidApp 是否只在 Application 上。
- 生成 Dagger 组件:框架帮你定义 Component、Subcomponent。
- 生成工厂类:为每个 @Provides 或 @Inject 构造函数生成 Factory。
- 触发 Dagger 编译:Dagger 接着生成最终的对象图代码。
这里有个关键点:Hilt 本质上是一个「编译器插件」,它不会在运行时做反射注入。所有依赖都在编译期确定好,运行时就是普通对象创建。这也是为什么 Hilt 比某些运行时 DI 框架更高效 —— 但代价就是编译错误更难排查。
为什么需要「额外请求诊断」?
你在项目中肯定遇到过类似场景:明明 @Provides 写了,也加了 @InstallIn,编译却报「找不到依赖」。更诡异的是,有时候加一个 @Singleton 就好了,去掉又坏。这背后就是 Hilt 的「额外请求」机制搞的鬼。
我管它叫「额外请求」,是指 Hilt 在生成代码时,会隐式地向 Dagger 请求一些你没有直接写的绑定。比如:
- 入口点扫描:@AndroidEntryPoint 标记的 Activity/Fragment 中,Hilt 会请求所有被 @Inject 的成员变量。
- 模块的依赖传递:一个 Module 里 @Provides 的方法参数,会被视为额外请求。
- 限定符冲突:两个相同类型但不同 @Qualifier 的绑定,Hilt 会请求一个明确的限定符。
- 组件作用域:@Singleton、@ActivityScoped 等作用域会要求对应的组件必须存在。
@Binds 或 @Provides 但你不记得自己写过时,八成就是 Hilt 的额外请求报错。这时候先看错误栈里的「requested by」字段。
Hilt 与 Dagger 的协作关系
它们的关系可以用一句话形容:Hilt 是前台老板,Dagger 是后台干活的。Hilt 处理完注解后,会把「半成品」交给 Dagger 继续处理生成最终代码。
| 阶段 | 由谁负责 | 产出 |
|---|---|---|
| 1. 注解处理 | Hilt 注解处理器 | Hilt_ 基类、组件接口、模块代理 |
| 2. 组件生成 | Dagger 注解处理器 | DaggerApplicationComponent 等实现类 |
| 3. 工厂合成 | Dagger 自动 | 各 Provide 方法的工厂类 |
| 4. 编译检查 | Dagger 编译期 | 依赖图合法性检查,报错或生成成功 |
看到了吧?编译时的报错多半来自 Dagger 那一步,但根因可能是 Hilt 的配置遗漏。所以诊断「额外请求」时,我们要能区分:是 Hilt 没生成正确的组件,还是 Dagger 在组件里找不到依赖。
知识体系总览
几类典型的额外请求场景
我根据项目踩坑经验,总结了三类最常见的「额外请求」陷阱:
- 跨模块依赖:你在 feature 模块里用 @Provides 提供了一个对象,但忘了 @InstallIn(SingletonComponent::class)。Hilt 会额外请求这个绑定,但因为组件不匹配,报错。
- 限定符隐式依赖:两个 @Module 里都用 @Named("api") 提供了相同类型,Hilt 必须额外请求一个 @Qualifier 来区分。如果你没写,它就报冲突。
- 入口点注解缺失:你在 Activity 里 @Inject 了一个 Presenter,但 Activity 没加 @AndroidEntryPoint。Hilt 会额外请求注入点,但找不到对应入口,编译失败。
为什么这门课要用「诊断」的视角?
你想想看,市面上讲 Hilt 的教程大多教你「怎么用」。但真到排错时,你打开编译输出,满屏的 Dagger 错误信息 —— 那就是天书。咱们这门课反过来:先搞懂 Hilt 在编译时做了什么「额外请求」,然后学会看诊断信息。
说白了,你不需要记住所有注解用法,只需要学会一个通用排查流程:
- 看错误栈里「requested by」字段 → 找到谁发起了请求
- 检查发起者的 @InstallIn 和组件作用域 → 确认组件匹配
- 检查绑定是否有冲突(重复、限定符缺失) → 修正代码
这个流程我用了两年,几乎能解决 95% 的编译时 DI 问题。后边的章节会一步步展开每个环节的具体技巧。