1. 前言
在现代 Android 开发中,依赖注入(DI) 和 状态管理 是构建健壮应用的关键。
- Hilt 是基于 Dagger 的官方 DI 框架,大幅简化了依赖注入的配置
- ViewModel 是 Jetpack 组件,用于管理 UI 相关数据并保持生命周期感知
本文全面总结 Hilt + ViewModel 在 Activity、Fragment 和 Compose 中的最佳实践
2. 基础配置
2.1 添加依赖
// Hilt
implementation "com.google.dagger:hilt-android:2.48"
kapt "com.google.dagger:hilt-compiler:2.48"// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2"// 生命周期协程
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.6.2"
2.2 启用 Hilt
@HiltAndroidApp
class MyApp : Application()
3. Activity 中的使用
3.1 定义 ViewModel
@HiltViewModel
class MainViewModel @Inject constructor(private val repo: UserRepository
) : ViewModel() {private val _user = MutableStateFlow<User?>(null)val user: StateFlow<User?> = _userfun loadUser() {viewModelScope.launch {_user.value = repo.getUser()}}
}
3.2 Activity 实现
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {private val vm: MainViewModel by viewModels()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)lifecycleScope.launch { // 使用 lifecycleScope.launchrepeatOnLifecycle(Lifecycle.State.STARTED) {vm.user.collect { user ->// 更新UI}}}vm.loadUser()}
}
关键点:
- 使用
lifecycleScope.launch
包裹collect
操作 - 配合
repeatOnLifecycle
确保只在 STARTED 状态收集数据 - 比
launchIn(lifecycleScope)
更直观且易于控制生命周期
4. Fragment 中的使用
4.1 Fragment 实现
@AndroidEntryPoint
class UserFragment : Fragment() {private val vm: UserViewModel by viewModels()override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)viewLifecycleOwner.lifecycleScope.launch { // 使用 viewLifecycleOwnerrepeatOnLifecycle(Lifecycle.State.STARTED) {vm.user.collect { user ->// 更新UI}}}}
}
优化点:
- 使用
viewLifecycleOwner
避免内存泄漏 - 协程自动随 Fragment 的 View 生命周期取消
5. Compose 中的使用
5.1 Composable 函数
@Composable
fun UserScreen(vm: UserViewModel = hiltViewModel()
) {val user by vm.user.collectAsStateWithLifecycle() // 自动处理生命周期LaunchedEffect(Unit) { // 替代 lifecycleScope.launchvm.loadUser()}UserProfile(user = user)
}
最佳实践:
- 使用
collectAsStateWithLifecycle()
替代手动生命周期管理 - 对一次性操作使用
LaunchedEffect
- 对需要手动控制的场景:
val lifecycle = LocalLifecycleOwner.current.lifecycle
DisposableEffect(lifecycle) {val observer = LifecycleEventObserver { _, event ->if (event == Lifecycle.Event.ON_START) {// 处理逻辑}}lifecycle.addObserver(observer)onDispose { lifecycle.removeObserver(observer) }
}
6. 混合使用 Hilt 和手动 Factory
6.1 手动 Factory 示例
class LegacyViewModel(private val param: String
) : ViewModel()class LegacyFactory(private val param: String) : ViewModelProvider.Factory {override fun <T : ViewModel> create(modelClass: Class<T>): T {return LegacyViewModel(param) as T}
}// 在 Fragment 中使用
class LegacyFragment : Fragment() {private val vm: LegacyViewModel by viewModels { LegacyFactory("param") }override fun onViewCreated(view: View, savedInstanceState: Bundle?) {viewLifecycleOwner.lifecycleScope.launch {// 处理协程}}
}
7. 生命周期管理对比
方式 | 优点 | 缺点 |
---|---|---|
lifecycleScope.launch | 生命周期控制更精确,代码更直观 | 需要手动管理取消 |
launchIn(lifecycleScope) | 代码简洁 | 生命周期控制不够直观 |
推荐使用模式:
lifecycleScope.launch {repeatOnLifecycle(Lifecycle.State.STARTED) {flow.collect { value ->// 处理数据}}
}
8. 常见问题解决方案
8.1 内存泄漏问题
// 错误示例
lifecycleScope.launch {vm.data.collect { } // 可能泄漏
}// 正确做法
viewLifecycleOwner.lifecycleScope.launch {repeatOnLifecycle(Lifecycle.State.STARTED) {vm.data.collect { }}
}
8.2 重复收集问题
// 使用 stateIn 共享流
val user = repo.getUserStream().stateIn(scope = viewModelScope,started = SharingStarted.WhileSubscribed(5000),initialValue = null)
9. 总结
最佳实践清单
-
Activity/Fragment:
- 使用
lifecycleScope.launch
+repeatOnLifecycle
- Fragment 务必使用
viewLifecycleOwner
- 使用
-
Compose:
- 优先使用
collectAsStateWithLifecycle()
- 复杂场景使用
LaunchedEffect
或DisposableEffect
- 优先使用
-
协程管理:
viewLifecycleOwner.lifecycleScope.launch {repeatOnLifecycle(Lifecycle.State.STARTED) {// 安全的数据收集} }
-
架构选择:
- 新项目统一使用
@HiltViewModel
- 旧项目逐步迁移,可混合使用手动 Factory
- 新项目统一使用
通过合理使用 Hilt 和 ViewModel,配合正确的协程生命周期管理,可以构建出:
- 更健壮的 Android 应用
- 更易维护的代码结构
- 更可靠的性能表现