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 注入的整体流程:

Hilt 依赖注入核心流程 @HiltAndroidApp Application SingletonComponent ActivityComponent @Module 提供依赖 @Inject constructor @AndroidEntryPoint Activity Hilt 自动根据注解生成 Component 树,Activity 从 ActivityComponent 获取依赖

我给你一个避坑指南: 注意 @HiltAndroidApp 必须在 Application 类上添加,否则 Hilt 不会生成任何 Component。我曾经在写测试 Demo 时忘了加,结果编译通过但运行时报 “Hilt Application is missing”,排查了半天才发现是这个小疏忽。

好,这就是 Hilt 入门的全部核心内容。

你可能会觉得现在还比较抽象,别急,在第 2 章我们会深入 Hilt 的 Module 和作用域,到时候我会结合具体的渲染性能案例来讲解依赖注入到底如何影响 UI 流畅度。