Android Hilt 教程 —— 一看就懂,一学就会
1. 什么是 Hilt?为什么要用 Hilt?
Hilt 是 Android 官方推荐的 依赖注入(DI)框架,基于 Dagger 开发,能够大大简化依赖注入的使用。
为什么要用 Hilt?
- 简化依赖注入:不需要手写复杂的 Dagger 代码,Hilt 提供了简单易懂的注解。
- 管理对象的生命周期:Hilt 会根据不同的组件(如 Activity、ViewModel、Application)自动管理依赖对象的创建和销毁。
- 提高代码的模块化:通过 Hilt 提供的 @Module,可以让代码更加清晰,方便维护和测试。
2. Hilt 的基本使用步骤
步骤 1:添加 Hilt 依赖
在 build.gradle (Project) 中添加 Hilt 插件:
buildscript {ext.hilt_version = '2.28-alpha'dependencies {classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"}
}新android studio 版本:
plugins {id 'com.google.dagger.hilt.android' version '2.51.1' apply false
}
在 app/build.gradle 中:
apply plugin: 'kotlin-kapt'
apply plugin: 'dagger.hilt.android.plugin'android {...
}dependencies {implementation("com.google.dagger:hilt-android:2.51.1")kapt("com.google.dagger:hilt-android-compiler:2.51.1")
}
注意: Hilt 需要 kotlin-kapt 来处理注解。
步骤 2:在 Application 级别启用 Hilt
创建一个继承 Application 的类,并添加 @HiltAndroidApp 注解。
import android.app.Application
import dagger.hilt.android.HiltAndroidApp@HiltAndroidApp
class MyApplication : Application()
作用: 让 Hilt 进行全局依赖注入的初始化。
步骤 3:在 Activity 中使用 Hilt 进行依赖注入
在 MainActivity 中使用 @AndroidEntryPoint 让 Hilt 自动提供对象:
import android.os.Bundle
import android.widget.TextView
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject@AndroidEntryPoint
class MainActivity : AppCompatActivity() {@Injectlateinit var someClass: SomeClass  // 直接注入对象private val viewModel: MainViewModel by viewModels()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)// 显示直接注入的结果val result1 = someClass.doSomething()findViewById<TextView>(R.id.tvDirectResult).text = "Direct injection: $result1"// 观察 ViewModel 的结果viewModel.doWork { result ->findViewById<TextView>(R.id.tvViewModelResult).text = "ViewModel: $result"}}
}
步骤 4:在 ViewModel 中使用 Hilt 进行依赖注入
ViewModel 不能直接使用 @Inject,需要 @HiltViewModel 注解:
import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject@HiltViewModel
class MainViewModel @Inject constructor(private val someClass: SomeClass,private val someOtherClass: SomeOtherClass
) : ViewModel() {fun doWork(callback: (String) -> Unit) {val result1 = someClass.doSomething()val result2 = someOtherClass.doSomething()callback("$result1, $result2")}
}
步骤 5:创建普通类并让 Hilt 提供实例
方法 1:直接使用 @Inject 注解(适用于简单对象)
 
如果是 没有构造参数 的类,可以直接用 @Inject 标注构造函数:
import javax.inject.Injectclass SomeClass @Inject constructor() {fun doSomething() = "Hello Hilt!"
}
Hilt 会自动创建 SomeClass 的实例,并在需要的地方注入。
方法 2:使用 @Module 提供实例(适用于需要配置的对象)
 
如果类 不能直接使用 @Inject(例如:构造函数需要参数),需要在 @Module 里提供:
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton@Module
@InstallIn(SingletonComponent::class)
object AppModule {@Provides@Singletonfun provideSomeOtherClass(): SomeOtherClass {return SomeOtherClass()}
}
然后创建 SomeOtherClass:
class SomeOtherClass {fun doSomething() = "Hello from SomeOtherClass!"
}
3. Hilt 的生命周期管理
Hilt 提供不同作用域,决定对象的生命周期:
- @Singleton—— 应用级,对象在整个应用生命周期内存在。
- @ActivityScoped—— Activity 级,对象在同一个 Activity 内共享。
- @ViewModelScoped—— ViewModel 级,对象绑定到- ViewModel的生命周期。
- @FragmentScoped—— Fragment 级,对象在同一个 Fragment 内共享。
例如,如果 SomeOtherClass 只在 Activity 级别存在:
@Module
@InstallIn(ActivityComponent::class)
object ActivityModule {@Provides@ActivityScopedfun provideSomeOtherClass(): SomeOtherClass {return SomeOtherClass()}
}
4. 总结:为什么选择 Hilt?
✅ 代码简洁:比 Dagger 需要更少的模板代码。
 ✅ 易学易用:通过注解即可完成依赖注入。
 ✅ 自动管理生命周期:减少手动管理实例的工作。
 ✅ 官方支持:推荐用于 Android 开发。
按照本教程,已经学会如何在 Activity、ViewModel 和 普通类 中使用 Hilt 进行依赖注入
二 @Inject 后面为什么需要加上constructor()
在 Kotlin 中,@Inject constructor() 主要用于 依赖注入,告诉 Hilt 如何创建 SomeClass 的实例。
1. 为什么 @Inject 需要加 constructor()?
 
在 Kotlin 里,constructor() 是 显式声明主构造函数 的方式,而 @Inject 只能标注 构造函数,不能直接标注类名。
例如:
class SomeClass @Inject constructor() { fun doSomething() = "Hello Hilt!"
}
这里 @Inject constructor() 表示:
- Hilt 需要通过这个构造函数来创建 SomeClass的实例。
- Hilt 发现 @Inject后,会自动提供SomeClass的对象,无需手动创建。
2. 如果不加 constructor 会怎样?
 
如果尝试这样写:
class SomeClass @Inject {  // ❌ 语法错误fun doSomething() = "Hello Hilt!"
}
会直接 编译错误,因为 @Inject 必须作用于构造函数,而 constructor 是构造函数的 显式声明方式。
3. constructor 省略的情况
 
当类没有显式的 constructor 关键字时,它默认是 无参构造函数:
class SomeClass {fun doSomething() = "Hello!"
}
但如果要让 Hilt 注入实例,必须 显式 写 @Inject constructor()。
4. 带参数的情况
如果 SomeClass 依赖其他类,比如 AnotherClass,Hilt 也能自动提供:
class AnotherClass @Inject constructor()class SomeClass @Inject constructor(private val anotherClass: AnotherClass) {fun doSomething() = "Using ${anotherClass.toString()}"
}
Hilt 会先创建 AnotherClass,然后再创建 SomeClass 并把 AnotherClass 传进去。
总结
✅ @Inject constructor() 是 Hilt 依赖注入的核心,告诉 Hilt 如何实例化一个类。
 ✅ 不能直接写 @Inject,必须加 constructor()。
 ✅ 如果类有依赖,Hilt 会自动提供并注入参数。
这样,Hilt 就能帮们自动管理 SomeClass 的创建,而不需要手动 new SomeClass() 了!
三 代码含义
1
// 观察 ViewModel 的结果
viewModel.doWork { result ->
findViewById<TextView>(R.id.tvViewModelResult).text = "ViewModel: $result"
}2 		
fun doWork(callback: (String) -> Unit) {
val result1 = someClass.doSomething()
val result2 = someOtherClass.doSomething()
callback("$result1, $result2")
} 
这段代码涉及 Lambda 回调 机制,它的作用是异步或延迟地获取 doWork 方法执行后的结果,并在外部(比如 UI 层)进行处理。
代码解析
1. 观察 ViewModel 的结果
viewModel.doWork { result ->findViewById<TextView>(R.id.tvViewModelResult).text = "ViewModel: $result"
}
- 这里 viewModel.doWork是一个方法,它接收一个 Lambda 回调,即{ result -> ... }。
- result是 doWork 方法执行完成后,回传的结果。
- findViewById<TextView>(R.id.tvViewModelResult).text = "ViewModel: $result"这行代码的意思是:当- doWork任务完成后,将- result赋值给- TextView,在 UI 界面显示出来。
2. doWork 方法定义
 
fun doWork(callback: (String) -> Unit) {val result1 = someClass.doSomething()val result2 = someOtherClass.doSomething()callback("$result1, $result2")
}
- doWork方法接收一个参数- callback,类型是- (String) -> Unit,即 一个以- String为参数、无返回值的 Lambda 表达式。
- someClass.doSomething()和- someOtherClass.doSomething()是执行的两个操作,它们可能返回字符串类型的结果。
- callback("$result1, $result2"):- 这个 callback就是上面调用doWork时传入的{ result -> ... }Lambda。
- "$result1, $result2"生成一个字符串,格式类似- "value1, value2"。
- 这个字符串作为参数,传递给 callback,从而调用{ result -> ... }代码块,并将"$result1, $result2"赋值给result。
 
- 这个 
result 是什么?
 
- result是- doWork任务执行后,回传给 Lambda 代码块的结果。
- 具体值取决于 someClass.doSomething()和someOtherClass.doSomething()的返回值。
callback("$result1, $result2") 是什么?
 
- callback("$result1, $result2")的作用是:- 生成一个字符串 "$result1, $result2"(比如"Hello, World")。
- 调用外部传入的 Lambda 代码块,并把这个字符串作为参数传递出去。
 
- 生成一个字符串 
执行流程示例
假设:
class SomeClass {fun doSomething(): String = "Hello"
}class SomeOtherClass {fun doSomething(): String = "World"
}val someClass = SomeClass()
val someOtherClass = SomeOtherClass()
那么 doWork 执行后:
doWork { result -> println("回调结果: $result") }
会输出:
回调结果: Hello, World
总结
- doWork方法执行后,- someClass.doSomething()和- someOtherClass.doSomething()生成两个字符串。
- callback("$result1, $result2")将它们拼接,并调用外部 Lambda 代码块,把结果传出去。
- result是 Lambda 代码块接收的参数,即- "Hello, World"这样的字符串。
- 在 viewModel.doWork调用时,最终TextView显示"ViewModel: Hello, World"。
这种方式适用于异步任务或解耦逻辑的情况,比如 网络请求、数据库操作、后台计算等,执行完成后用回调通知 UI 层更新数据。
四 手动 clean + build
Build → Clean Project
 Build → Rebuild Project
五 Android Hilt 入门教程(补充)
Hilt 是 Android 官方推荐的 依赖注入框架,它基于 Dagger,简化了依赖管理,适用于 MVVM 架构,提高了代码的可维护性。
1️⃣ 为什么要用 Hilt?
在 Android 开发中,们通常需要手动创建和管理对象,例如 ViewModel、Repository、Retrofit 等。Hilt 可以自动管理这些对象的创建和生命周期,让们专注于业务逻辑,而不是手动实例化对象。
✅ Hilt 的优点:
 ✔️ 自动管理依赖,避免手动创建实例
 ✔️ ViewModel 支持,与 Jetpack 组件无缝集成
 ✔️ 作用域管理,不同组件(Activity、Fragment)能获得合适的对象
 ✔️ 简化 Dagger 依赖注入,代码更简洁
2️⃣ Hilt 的基本使用
📌(1)添加 Hilt 依赖
与第一点相同
plugins {id("com.android.application")id("kotlin-android")id("kotlin-kapt")id("com.google.dagger.hilt.android")
}android {namespace 'com.test.hiltstudy'compileSdk 35defaultConfig {applicationId "com.test.hiltstudy"minSdk 24targetSdk 35versionCode 1versionName "1.0"testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}compileOptions {sourceCompatibility JavaVersion.VERSION_1_8targetCompatibility JavaVersion.VERSION_1_8}kotlinOptions {jvmTarget = '1.8'}
}Allow references to generated code
//kapt {
//    correctErrorTypes true
//}dependencies {implementation libs.androidx.core.ktximplementation libs.androidx.appcompatimplementation libs.materialimplementation libs.androidx.activityimplementation libs.androidx.constraintlayouttestImplementation libs.junitandroidTestImplementation libs.androidx.junitandroidTestImplementation libs.androidx.espresso.core// Hilt Dependenciesimplementation("com.google.dagger:hilt-android:2.51.1")kapt("com.google.dagger:hilt-android-compiler:2.51.1")// Fragment KTX for viewModels() delegateimplementation("androidx.fragment:fragment-ktx:1.6.2")// ViewModel
//    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2")
//    implementation("androidx.activity:activity-ktx:1.8.1")
//retrofitimplementation("com.squareup.retrofit2:converter-gson:2.9.0")}
📌(2)初始化 Hilt
在 AndroidManifest.xml:
<applicationandroid:name=".MyApplication"...>
</application>
然后创建 MyApplication.kt:
@HiltAndroidApp
class MyApplication : Application()
🔹 @HiltAndroidApp 用于初始化 Hilt,它会在 App 启动时配置依赖注入。
📌(3)在 Activity/Fragment 使用 Hilt
在 Activity 里启用 Hilt
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {@Injectlateinit var someClass: SomeClass  // 自动注入
}
🔹 @AndroidEntryPoint 标记 Activity 以支持 Hilt
 🔹 @Inject lateinit var someClass: SomeClass 直接注入对象
在 Fragment 里启用 Hilt
@AndroidEntryPoint
class MainFragment : Fragment() {@Injectlateinit var someRepository: SomeRepository
}
💡 Activity 和 Fragment 都必须加 @AndroidEntryPoint 才能使用 Hilt 注入的对象!
📌(4)在 ViewModel 里使用 Hilt
@HiltViewModel
class MainViewModel @Inject constructor(private val repository: SomeRepository
) : ViewModel() {fun fetchData() = repository.getData()
}
在 Activity 或 Fragment 里:
private val viewModel: MainViewModel by viewModels()
🔹 Hilt 自动创建 MainViewModel,不用 ViewModelProvider 手动实例化。
📌(5)创建 Hilt 模块(Module)
如果 SomeRepository 不能用 @Inject 直接构造,比如 Retrofit,们需要 使用 Module 提供实例:
@Module
@InstallIn(SingletonComponent::class) // 作用于整个应用生命周期
object AppModule {@Provides@Singletonfun provideRetrofit(): Retrofit {return Retrofit.Builder().baseUrl("https://api.example.com/").addConverterFactory(GsonConverterFactory.create()).build()}@Provides@Singletonfun provideApiService(retrofit: Retrofit): ApiService {return retrofit.create(ApiService::class.java)}
}
🔹 @Module 标记为 Hilt 模块
 🔹 @Provides 提供依赖
 🔹 @Singleton 表示单例
3️⃣ Hilt 作用域
| 作用域 | 说明 | 示例 | 
|---|---|---|
| @Singleton | 全局单例,应用级共享 | Retrofit、数据库 | 
| @ActivityScoped | 只在 Activity 里共享 | 共享 ViewModel | 
| @ViewModelScoped | 只在 ViewModel 里共享 | Repository | 
4️⃣ Hilt 实战示例
1️⃣ 创建一个 Repository
class SomeRepository @Inject constructor() {fun getData(): String = "Hello from Repository"
}
2️⃣ 在 ViewModel 里注入
@HiltViewModel
class MainViewModel @Inject constructor(private val repository: SomeRepository
) : ViewModel() {fun fetchData(): String = repository.getData()
}
3️⃣ 在 Activity 里获取数据
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {private val viewModel: MainViewModel by viewModels()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)findViewById<TextView>(R.id.textView).text = viewModel.fetchData()}
}
✅ 运行后,TextView 显示 "Hello from Repository" 🎉
5️⃣ 总结
🔹 @HiltAndroidApp 让应用支持 Hilt
 🔹 @AndroidEntryPoint 用于 Activity/Fragment
 🔹 @HiltViewModel 用于 ViewModel
 🔹 @Inject 直接注入类实例
 🔹 @Module + @Provides 提供无法直接注入的对象(如 Retrofit)
 🔹 @Singleton、@ActivityScoped 控制对象生命周期
Hilt 让 依赖注入变得简单高效,可以自动管理对象,提升代码的可维护性。
五 为什么MainActivity 等类都必须写Hilt注解
 
- 当在 MainActivity中使用by viewModels()时,Android 系统需要创建MainViewModel的实例
- MainViewModel的构造函数需要一个- SomeRepository参数
- 由于 SomeRepository使用了@Inject注解,它只能通过 Hilt 的依赖注入系统来创建和管理
这就造成了一个依赖链:
- MainActivity需要- MainViewModel
- MainViewModel需要- SomeRepository
- SomeRepository由 Hilt 管理
所以当使用了 Hilt 来管理某个依赖(如 SomeRepository)时,所有需要使用这个依赖的类(如 MainViewModel)也必须通过 Hilt 来管理。这不是"强行绑定",而是依赖注入系统工作的必然要求。
如果不想使用 Hilt,需要:
- 移除 SomeRepository的@Inject注解
- 手动创建 SomeRepository和MainViewModel的实例
- 实现自定义的 ViewModelFactory
但这样会失去依赖注入带来的好处,如:
- 依赖的自动管理
- 生命周期的自动处理
- 测试时依赖的容易替换
- 代码的解耦
六 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对应 Application
- ActivityComponent对应 Activity
- ViewModelComponent对应 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()}
}
八 Hilt为什么是解耦利器 和测试友好助手
Hilt 之所以被称为 “解耦利器” 和 “测试友好助手”,是因为它能让 类之间的依赖关系更加松散,并且 支持在测试时轻松替换依赖。
我们从 解耦(Decoupling) 和 测试友好(Testability) 两个方面分别解释,并提供示例代码来说明。
🎯 1. Hilt 是如何解耦代码的?
✅ 传统写法(紧耦合,难以扩展)
class MyRepository {private val apiService = ApiService()  // 直接创建实例(强依赖)fun fetchData(): String {return apiService.getData()}
}
❌ 问题
- MyRepository直接依赖- ApiService,导致:- 难以替换(如果要改用 FakeApiService进行测试,就得修改MyRepository代码)
- 扩展性差(如果 ApiService需要不同的实现方式,就得改MyRepository)
- 不适合单元测试(不能注入模拟数据)
 
- 难以替换(如果要改用 
✅ 使用 Hilt 进行解耦
class MyRepository @Inject constructor(private val apiService: ApiService) {fun fetchData(): String {return apiService.getData()}
}
Hilt 提供的 ApiService 实例
 
@Module
@InstallIn(SingletonComponent::class)
object AppModule {@Provides@Singletonfun provideApiService(): ApiService {return RealApiService()}
}
✅ 解耦优势
- MyRepository 只依赖 ApiService抽象,不关心ApiService具体是怎么来的
- 可以轻松替换 ApiService(比如切换到FakeApiService进行测试)
- 代码更清晰,职责更明确(Hilt负责管理依赖,不再手动new)
🔬 2. Hilt 是如何让测试变得更简单的?
Hilt 允许我们在测试时 替换真实依赖,避免复杂的网络请求、数据库操作等,从而更快、更稳定地测试业务逻辑。
✅ 1. 不使用 Hilt,测试困难
@Test
fun testFetchData() {val repo = MyRepository(ApiService())  // 依赖真实的 ApiServiceval result = repo.fetchData()assertEquals("Expected Data", result)  // 可能失败,因为是真实数据
}
❌ 问题
- MyRepository无法使用 Mock 依赖
- 每次测试都会访问真实 API(影响速度、可能失败)
- 代码可测试性 非常低
✅ 2. 使用 Hilt 轻松替换依赖
🛠️ 在测试中提供 FakeApiService
 
@HiltAndroidTest
@UninstallModules(AppModule::class) // 先卸载正式模块
class MyRepositoryTest {@Module@InstallIn(SingletonComponent::class)object TestModule {@Providesfun provideFakeApiService(): ApiService {return object : ApiService {override fun getData(): String {return "Fake Data"}}}}@Injectlateinit var repository: MyRepository@get:Rulevar hiltRule = HiltAndroidRule(this)@Beforefun setup() {hiltRule.inject()  // 让 Hilt 注入测试依赖}@Testfun testFetchData() {val result = repository.fetchData()assertEquals("Fake Data", result)  // 100% 可预测的测试结果}
}
✅ 测试优势
- 自动替换真实依赖(不再访问网络或数据库)
- 测试速度更快(不依赖外部服务)
- Mock 数据可预测(不会受外部 API 变动影响)
📌 总结
| 特点 | 传统依赖方式 | 使用 Hilt | 
|---|---|---|
| 代码解耦 | 直接 new对象,强依赖具体实现 | 依赖抽象,Hilt 负责提供实现 | 
| 可扩展性 | 变更时需要修改多个类 | 只需修改 @Module提供的依赖 | 
| 测试友好 | 依赖真实 API,难以 Mock | 轻松替换 Mock 依赖,提高测试效率 | 
| 代码可维护性 | 依赖关系混乱,难以管理 | 依赖关系清晰,代码模块化 | 
🚀 一句话总结
Hilt = 解耦利器 + 测试友好助手,让的代码 更模块化、更易测试、更易维护!
九 Hilt为什么是对象工厂 和 生命周期管家 ?
Hilt 之所以是 对象工厂 和 生命周期管家,是因为它能够 自动创建并管理依赖对象,并且可以 自动适配依赖对象的生命周期,避免手动管理带来的复杂性和潜在的内存泄漏。
🎭 1. Hilt 是对象工厂(自动创建并管理依赖对象)
在没有 Hilt 的情况下,我们通常需要手动创建对象:
class MyRepository {private val apiService = ApiService()  // 直接创建实例
}
❌ 问题
- MyRepository依赖- ApiService,必须手动- new,不灵活
- 如果 ApiService还依赖Retrofit,就需要new多个对象,依赖链复杂
✅ Hilt 作为对象工厂
Hilt 通过 @Module + @Provides 或 @Inject 构造注入 自动创建对象:
class MyRepository @Inject constructor(private val apiService: ApiService) { }
Hilt 自动提供 ApiService 实例
 
@Module
@InstallIn(SingletonComponent::class)
object AppModule {@Provides@Singletonfun provideApiService(): ApiService {return Retrofit.Builder().baseUrl("https://api.example.com/").addConverterFactory(GsonConverterFactory.create()).build().create(ApiService::class.java)}
}
🎯 关键点
- Hilt 自动创建 ApiService,并将其注入到MyRepository
- 我们不需要手动 new,Hilt 充当工厂,自动提供对象
- 如果 ApiService还有依赖(如Retrofit),Hilt 也会自动解析并注入
🕰️ 2. Hilt 是生命周期管家(自动管理对象生命周期)
在 Android 开发中,不同作用域的对象需要不同的生命周期,比如:
- Application 级别的单例(整个应用共享)
- Activity 级别的实例(Activity 销毁时自动清理)
- Fragment 级别的实例(Fragment 关闭时释放)
❌ 传统方式:手动管理生命周期
class MainActivity : AppCompatActivity() {private val repository = MyRepository(ApiService()) // 手动创建,难以管理
}
❌ 问题
- 全局变量会导致内存泄漏
- Activity 重建(如旋转屏幕)后,数据可能丢失
- 手动管理生命周期非常繁琐
✅ Hilt 自动管理生命周期
Hilt 通过作用域(@InstallIn(Component::class))自动匹配生命周期:
🎯 Application 作用域(全局单例)
@InstallIn(SingletonComponent::class) // Application 级别
@Module
object AppModule {@Provides@Singletonfun provideMyRepository(apiService: ApiService): MyRepository {return MyRepository(apiService)}
}
- 全局单例:SingletonComponent作用域下的对象,整个应用生命周期内存储
- 避免重复创建:所有使用 MyRepository的地方,都共享同一个实例
🎯 Activity 作用域(Activity 级别)
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {private val viewModel: MainViewModel by viewModels() // Hilt 自动管理生命周期
}
@HiltViewModel
class MainViewModel @Inject constructor(private val repository: MyRepository
) : ViewModel()
- @HiltViewModel绑定 ViewModel 生命周期,当- Activity关闭时,ViewModel 也会自动销毁
- MyRepository仍然是- Singleton作用域的,所以- MainViewModel依赖它,但不会重复创建
🎯 Fragment 作用域
如果 Fragment 需要自己的 ViewModel:
@AndroidEntryPoint
class MyFragment : Fragment() {private val viewModel: MyViewModel by viewModels()
}
@HiltViewModel
class MyViewModel @Inject constructor(private val repository: MyRepository
) : ViewModel()
- MyViewModel与- Fragment绑定,Fragment 销毁时自动释放
- 不会因为 Activity变化导致数据丢失
📌 结论
| 特性 | 传统方式 | 使用 Hilt | 
|---|---|---|
| 对象管理 | 手动 new,难以管理 | Hilt 自动创建并管理依赖 | 
| 依赖关系 | 需要手动传递依赖 | Hilt 通过 @Inject自动注入 | 
| 生命周期管理 | 需要手动释放对象,避免内存泄漏 | Hilt 自动匹配对象生命周期 | 
| 测试支持 | 需要大量 Mock | Hilt 允许轻松替换依赖 | 
💡 总结
Hilt 作为 “对象工厂”,自动创建并管理依赖对象
Hilt 作为 “生命周期管家”,自动管理作用域,防止内存泄漏
这样,我们就能更专注于业务逻辑,而不用操心依赖创建和生命周期管理!
十 @Inject注解
@Inject 是 Hilt 依赖注入的核心注解,它的作用是 让 Hilt 知道如何创建和提供一个类的实例,从而 自动管理对象的依赖关系。提到的两种使用方式(构造函数注入 和 字段注入)确实是 @Inject 的两个关键用途,下面详细解释。
📌 1. @Inject 作用之一:构造函数注入
 
构造函数注入(Constructor Injection)用于 告诉 Hilt 如何创建一个类的实例。当一个类的构造函数上加上 @Inject,Hilt 就会自动知道如何实例化它。
✅ 示例
class SomeClass @Inject constructor() {fun doSomething() = "Hello Hilt!"
}
- @Inject constructor()告诉 Hilt 这个类可以被自动创建,无需手动- new SomeClass()
- 任何需要 SomeClass的地方,Hilt 都可以自动提供它
- 适用于 无状态类(即不需要复杂的初始化)
🚀 使用 @Inject 的优势
 
✅ 无需手动 new 对象,Hilt 负责实例化
 ✅ 减少样板代码,避免工厂模式(Factory)或手写依赖注入
 ✅ 保证依赖一致性,不会意外创建多个 SomeClass 实例
📌 2. @Inject 作用之二:字段注入
 
字段注入(Field Injection)用于 在类内部自动注入依赖对象,通常用于 Activity、Fragment 或 ViewModel,因为它们的实例是由 Android 框架创建的,不能使用构造函数注入。
✅ 示例
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {@Injectlateinit var someClass: SomeClass  // 自动注入override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)// 使用被 Hilt 自动注入的对象Log.d("HiltExample", someClass.doSomething()) // 输出 "Hello Hilt!"}
}
📌 关键点
- @Inject lateinit var someClass: SomeClass- 让 Hilt 自动创建 SomeClass实例,并注入到someClass变量中
- 不需要 new SomeClass()
 
- 让 Hilt 自动创建 
- @AndroidEntryPoint必须加在- Activity或- Fragment上,否则 Hilt 无法注入- 这是因为 Activity和Fragment由 Android 框架管理,Hilt 需要特殊处理它们的依赖注入
 
- 这是因为 
🚀 使用 @Inject 的优势
 
✅ Hilt 自动创建并注入实例,无需手动初始化
 ✅ 避免 lateinit 为空的问题,Hilt 负责对象生命周期
 ✅ 简化依赖管理,代码更清晰、可维护性更强
📌 3. @Inject 与 Hilt 作用域
 
不同的 @Inject 依赖可以拥有不同的生命周期
 
@Singleton
class SomeSingletonClass @Inject constructor()
- 这个 SomeSingletonClass只会被创建一次,整个应用生命周期都能共享
- Hilt 自动管理它的生命周期,不会意外地创建多个实例
不同作用域示例:
@ActivityScoped
class SomeActivityScopedClass @Inject constructor()
- ActivityScoped:每个 Activity 会有自己的实例
- SingletonComponent:全局单例
- ViewModelScoped:与 ViewModel 生命周期一致
📌 4. @Inject 不能用于接口,需要 @Module 提供
 
如果 @Inject 用在 接口 上,会报错:
interface ApiService {fun fetchData(): String
}
❌ 直接 @Inject 不行:
 
class ApiServiceImpl @Inject constructor() : ApiService {override fun fetchData() = "API Data"
}
👉 必须使用 @Module 提供接口实例
@Module
@InstallIn(SingletonComponent::class)
object AppModule {@Providesfun provideApiService(): ApiService {return ApiServiceImpl()}
}
📌 关键点
- 如果是普通类,@Inject constructor()就够了
- 如果是接口,必须用 @Module和@Provides提供
🎯 结论
| 方式 | 使用场景 | 作用 | 
|---|---|---|
| @Inject constructor() | 普通类 | 让 Hilt 知道如何创建这个类 | 
| @Inject lateinit var | Activity、Fragment、ViewModel | 让 Hilt 自动注入对象实例 | 
| @Module + @Provides | 接口或第三方库 | 让 Hilt 提供无法直接 @Inject的对象 | 
🚀 一句话总结
@Inject让 Hilt 知道如何创建对象,而@Inject lateinit var让 Hilt 自动注入对象!
十一 Hilt其他注解
在 Android Hilt 中,除了 @Inject 之外,还有多个核心注解,它们负责不同的依赖注入功能,包括作用域管理、模块提供依赖、绑定接口、生命周期管理等。以下是 Hilt 的核心注解及其详细解析,并附上代码示例。
📌 1. @HiltAndroidApp
 
作用:
- 标记 Application类,让 Hilt 生成依赖注入的代码
- 必须 在 Application类上使用
✅ 示例
@HiltAndroidApp
class MyApplication : Application()
🚀 关键点
✅ Hilt 会在应用启动时初始化依赖注入
 ✅ 生成 Hilt_MyApplication 代码,Hilt 依赖的入口
 ✅ 必须加,否则 Hilt 无法工作
📌 2. @AndroidEntryPoint
 
作用:
- 用于 Activity、Fragment、Service等,让它们支持 Hilt 依赖注入
- 必须加,否则 Hilt 无法注入对象
✅ 示例
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {@Injectlateinit var someClass: SomeClass  // 自动注入
}
🚀 关键点
✅ Activity、Fragment、Service 必须加,否则 @Inject 不会生效
 ✅ Hilt 会自动在内部生成依赖注入代码
 ✅ Fragment 依赖的 Activity 也必须有 @AndroidEntryPoint,否则会崩溃
📌 3. @Inject
 
作用:
- 用于 构造函数 或 字段,让 Hilt 知道如何创建和注入对象
✅ 示例
构造函数注入
class SomeClass @Inject constructor() {fun doSomething() = "Hello Hilt!"
}
字段注入
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {@Injectlateinit var someClass: SomeClass
}
🚀 关键点
✅ 构造函数上加 @Inject,Hilt 知道如何创建对象
 ✅ 字段加 @Inject,Hilt 会自动提供依赖
📌 4. @Module + @InstallIn
 
作用:
- 提供无法直接 @Inject的对象(如接口、第三方库)
- 定义依赖的作用域
✅ 示例
@Module
@InstallIn(SingletonComponent::class) // 全局单例
object AppModule {@Provides@Singletonfun provideApiService(): ApiService {return Retrofit.Builder().baseUrl("https://api.example.com/").addConverterFactory(GsonConverterFactory.create()).build().create(ApiService::class.java)}
}
🚀 关键点
✅ @Module 让 Hilt 知道这里提供依赖
 ✅ @InstallIn 确定依赖的作用域(SingletonComponent 表示全局单例)
📌 5. @Provides
 
作用:
- 提供对象实例(适用于无法 @Inject的情况,如第三方库)
✅ 示例
@Module
@InstallIn(SingletonComponent::class)
object AppModule {@Providesfun provideSomeClass(): SomeClass {return SomeClass()}
}
🚀 关键点
✅ 如果 SomeClass 不能 @Inject,就用 @Provides 提供
 ✅ 返回类型就是 Hilt 提供的类型
📌 6. @Binds
 
作用:
- 用于接口的实现绑定
- 比 @Provides更高效(少了一次方法调用)
✅ 示例
interface ApiService {fun fetchData(): String
}class ApiServiceImpl @Inject constructor() : ApiService {override fun fetchData() = "API Data"
}@Module
@InstallIn(SingletonComponent::class)
abstract class AppModule {@Bindsabstract fun bindApiService(impl: ApiServiceImpl): ApiService
}
🚀 关键点
✅ @Binds 只能用于 abstract 方法,不能有逻辑
 ✅ 比 @Provides 更高效,但 @Provides 更灵活
📌 7. 作用域注解
作用:
- 控制 对象的生命周期,防止重复创建
- 适用于 @Provides或@Inject提供的对象
✅ 示例
@Singleton
class SomeSingletonClass @Inject constructor()
| 作用域 | 适用范围 | 生命周期 | 
|---|---|---|
| SingletonComponent | 全局 | 应用生命周期 | 
| ActivityRetainedComponent | ViewModel | Activity 重新创建时依然存在 | 
| ActivityComponent | Activity | Activity 销毁时释放 | 
| FragmentComponent | Fragment | Fragment 销毁时释放 | 
📌 8. @HiltViewModel
 
作用:
- 让 ViewModel 支持 Hilt 注入
- 简化 ViewModel 创建
✅ 示例
@HiltViewModel
class MainViewModel @Inject constructor(private val repository: MyRepository
) : ViewModel()
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {private val viewModel: MainViewModel by viewModels()
}
🚀 关键点
✅ @HiltViewModel 必须配合 @AndroidEntryPoint 的 Activity 或 Fragment
 ✅ ViewModel 不用手动创建,Hilt 自动管理
📌 9. @EntryPoint
 
作用:
- 用于无法使用 @AndroidEntryPoint的类
- 如 ContentProvider、BroadcastReceiver
✅ 示例
@EntryPoint
@InstallIn(SingletonComponent::class)
interface MyEntryPoint {fun getSomeClass(): SomeClass
}// 使用 EntryPoint
val someClass = EntryPointAccessors.fromApplication(context, MyEntryPoint::class.java).getSomeClass()
🚀 关键点
✅ 适用于无法直接 @Inject 的情况
 ✅ Hilt 依然能提供依赖
🎯 结论
| 注解 | 作用 | 
|---|---|
| @HiltAndroidApp | 让 Hilt 初始化依赖注入(必须加在 Application) | 
| @AndroidEntryPoint | 让 Activity、Fragment、Service支持 Hilt | 
| @Inject | 构造函数注入 & 字段注入 | 
| @Module+@InstallIn | 提供无法 @Inject的依赖 | 
| @Provides | 直接提供实例(如第三方库) | 
| @Binds | 绑定接口实现(比 @Provides高效) | 
| @Singleton | 作用域管理(全局单例) | 
| @HiltViewModel | Hilt ViewModel 支持 | 
| @EntryPoint | 用于 BroadcastReceiver、ContentProvider | 
🚀 总结:Hilt 通过 @Inject、@Module、@Provides 等注解,让 对象创建 & 生命周期管理 自动化,大幅减少样板代码,提高可维护性!
参考
google Hilt 教程
