Android Hilt 入门教程_Hilt原理
一 Hilt 管理对象的原理
Hilt 是基于 Dagger 的 依赖注入(Dependency Injection, DI)框架。它在编译期生成代码,自动管理对象的创建、注入和生命周期。
1️⃣ 自动管理依赖(对象创建)原理
当写:
class MyRepository @Inject constructor(private val apiService: ApiService
)
Hilt 会在 编译期生成一段 Dagger 代码,负责:
- 创建
MyRepository - 自动找到
ApiService的实例(如果也可以被@Inject或@Provides)
👉 总结:
Hilt 使用 @Inject 和 @Module + @Provides 来定义 对象之间的依赖关系图,并在编译时生成创建这些对象的代码。
2️⃣ 生命周期的自动处理
Hilt 把依赖对象和 Android 组件的生命周期绑定在一起,通过作用域注解(Scope)来完成。
🧩 作用域示例:
| 注解 | 生命周期 | 示例 |
|---|---|---|
@Singleton | 应用级别(Application 生命周期) | Retrofit、Room |
@ActivityScoped | 绑定到某个 Activity 生命周期 | 当前 Activity 的共享依赖 |
@ViewModelScoped | ViewModel 生命周期 | 当前 ViewModel 独享的对象 |
✅ 原理:
Hilt 在每个作用域下生成一个 Dagger 组件(Component):
SingletonComponent对应 ApplicationActivityComponent对应 ActivityViewModelComponent对应 ViewModel- …
这些组件管理它们生命周期内的对象,只要组件存在,对象就一直存活;组件销毁,对象就自动释放。
3️⃣ 测试时依赖容易替换(可插拔)
Hilt 支持测试环境下 替换真实依赖为 Mock 或 Fake,这是 DI 的巨大优势。
✅ 替换方式:
@HiltAndroidTest
@UninstallModules(AppModule::class) // 卸载正式模块
class MyTest {@Module@InstallIn(SingletonComponent::class)object TestModule {@Providesfun provideFakeApi(): ApiService = FakeApiService()}
}
✅ 测试时,Hilt 用 TestModule 替换 AppModule,让测试逻辑而不是网络。
4️⃣ 解耦代码的核心原理
✅ 传统写法(耦合):
val repo = MyRepository(ApiService())
MyRepository硬编码依赖了ApiService,不利于替换、扩展、测试。
✅ Hilt 写法(解耦):
class MyRepository @Inject constructor(private val api: ApiService)
MyRepository只依赖 抽象接口ApiService是由外部(Hilt)提供,未来替换为FakeApiService不用改业务逻辑- 解耦 = 高扩展性 + 高可测试性
🔧 总结原理图(类比管道工厂)
| Hilt 功能 | 原理 | 类比 |
|---|---|---|
| 自动注入 | 编译期生成依赖图 | 自动搭建水管连接 |
| 生命周期管理 | 每个作用域有专属组件管理对象 | 活水池(组件)存在水就流动(对象存活) |
| 测试替换 | 支持模块替换 | 换水源(Fake)测试流速(逻辑) |
| 解耦结构 | 依赖抽象、注入实现 | 插拔模块化水管,便于维护 |
🚀 总结一句话:
Hilt = 编译期生成对象工厂 + 生命周期管家 + 解耦利器 + 测试友好助手,让写少但可维护性更高的代码。
儿 Hilt 依赖注入结构图解
🧠 Hilt 架构核心
+---------------------------+| Application || (HiltApplication class) || @HiltAndroidApp |+---------------------------+|v+---------------------------+| SingletonComponent || @InstallIn(Singleton...) || -> Retrofit, Room, Repo |+---------------------------+|v+---------------------------+| ActivityComponent || @InstallIn(Activity...) || -> Activity 作用域对象 |+---------------------------+|v+---------------------------+| ViewModelComponent || @HiltViewModel || -> ViewModel 的依赖 |+---------------------------+|v+---------------------------+| FragmentComponent || @AndroidEntryPoint || -> Fragment 注入依赖 |+---------------------------+
当然可以!下面是 **Hilt 的内部结构原理图解** 的 `.md`(Markdown)格式说明,适合用于技术文档、GitHub README 或团队协作文档中:---```md
# 🛠️ Hilt 依赖注入结构图解## 🧠 Hilt 架构核心```plaintext+---------------------------+| Application || (HiltApplication class) || @HiltAndroidApp |+---------------------------+|v+---------------------------+| SingletonComponent || @InstallIn(Singleton...) || -> Retrofit, Room, Repo |+---------------------------+|v+---------------------------+| ActivityComponent || @InstallIn(Activity...) || -> Activity 作用域对象 |+---------------------------+|v+---------------------------+| ViewModelComponent || @HiltViewModel || -> ViewModel 的依赖 |+---------------------------+|v+---------------------------+| FragmentComponent || @AndroidEntryPoint || -> Fragment 注入依赖 |+---------------------------+
🧩 作用域绑定关系
| 组件类型 | 对应生命周期 | 示例依赖项 |
|---|---|---|
SingletonComponent | Application 全局单例 | Retrofit、数据库等 |
ActivityComponent | 每个 Activity 独立 | 当前 Activity 的共享依赖 |
ViewModelComponent | 每个 ViewModel 独立 | 仓库、业务类 |
FragmentComponent | 每个 Fragment 独立 | 当前 Fragment 的依赖 |
🔄 流程示意(依赖注入过程)
1. App 启动时,Hilt 生成 SingletonComponent
2. Activity 启动时,注入 ActivityComponent 作用域依赖
3. Fragment 加载时,注入 FragmentComponent 作用域依赖
4. ViewModel 被创建时,注入 ViewModelComponent 中依赖
5. 每个 Component 都可以从其上层 Component 获取依赖
✅ 示例:自动注入过程
// 注入 ViewModel
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {private val viewModel: MainViewModel by viewModels()
}// 提供依赖
@HiltViewModel
class MainViewModel @Inject constructor(private val repo: SomeRepository
) : ViewModel()// 仓库依赖提供
class SomeRepository @Inject constructor(private val api: ApiService
)
🧪 测试支持
@HiltAndroidTest
@UninstallModules(AppModule::class)
class MyTest {@Module@InstallIn(SingletonComponent::class)object TestModule {@Providesfun provideFakeApi(): ApiService = FakeApiService()}
}
三 为什么MainActivity 等类都必须写Hilt注解
- 当在
MainActivity中使用by viewModels()时,Android 系统需要创建MainViewModel的实例 MainViewModel的构造函数需要一个SomeRepository参数- 由于
SomeRepository使用了@Inject注解,它只能通过 Hilt 的依赖注入系统来创建和管理
这就造成了一个依赖链:
MainActivity需要MainViewModelMainViewModel需要SomeRepositorySomeRepository由 Hilt 管理
所以当使用了 Hilt 来管理某个依赖(如 SomeRepository)时,所有需要使用这个依赖的类(如 MainViewModel)也必须通过 Hilt 来管理。这不是"强行绑定",而是依赖注入系统工作的必然要求。
如果不想使用 Hilt,需要:
- 移除
SomeRepository的@Inject注解 - 手动创建
SomeRepository和MainViewModel的实例 - 实现自定义的
ViewModelFactory
但这样会失去依赖注入带来的好处,如:
- 依赖的自动管理
- 生命周期的自动处理
- 测试时依赖的容易替换
- 代码的解耦
