Android Hilt 入门教程_传统写法和Hilt写法的比较
一 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 作为 “生命周期管家”,自动管理作用域,防止内存泄漏
这样,我们就能更专注于业务逻辑,而不用操心依赖创建和生命周期管理!
