Kotlin ViewModel 全流程指南
ViewModel 的核心作用是以注重生命周期的方式存储和管理界面相关的数据。它最伟大的地方在于:当手机屏幕旋转(配置更改)导致 Activity 重建时,ViewModel 中的数据不会丢失。
大纲
- 添加依赖
- [创建 ViewModel 类](#创建 ViewModel 类)
- 在-activity-或-fragment-中初始化
- [ViewModel 的生命周期](#ViewModel 的生命周期)
- [核心准则 Best Practices](#核心准则 Best Practices)
- 总结
1. 添加依赖
在 build.gradle.kts (Module: app) 中添加 Lifecycle 库:
kotlin
dependencies {
val lifecycle_version = "2.8.0" // 请检查最新版本
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version")
// 如果在 Activity/Fragment 中使用 'by viewModels()' 扩展
implementation("androidx.activity:activity-ktx:1.9.0")
}
2. 创建 ViewModel 类
ViewModel 应该存放所有的 UI 数据逻辑。建议配合 StateFlow 或 LiveData 使用,以实现响应式编程。
kotlin
import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
class MyViewModel : ViewModel() {
// 使用 StateFlow 管理状态
private val _counter = MutableStateFlow(0)
val counter: StateFlow<Int> = _counter
fun incrementCounter() {
_counter.value += 1
}
}
3. 在 Activity 或 Fragment 中初始化
⚠️ 千万不要直接通过
val vm = MyViewModel()来实例化,否则它就失去了生命周期感知的特性。必须通过 ViewModelProvider 或by viewModels()委托。
3.1 在 Activity 中
kotlin
class MainActivity : AppCompatActivity() {
// 使用 ktx 扩展函数(推荐)
private val viewModel: MyViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 观察数据变化(以 Flow 为例)
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.counter.collect { count ->
// 更新 UI,例如:textView.text = count.toString()
}
}
}
}
}
3.2 在 Fragment 中(共享 ViewModel)
如果你希望 Fragment 之间共享数据,可以使用 activityViewModels()。
kotlin
class MyFragment : Fragment() {
// 与宿主 Activity 共享同一个 ViewModel 实例
private val sharedViewModel: MyViewModel by activityViewModels()
}
4. ViewModel 的生命周期
理解 ViewModel 的生命周期至关重要。它的存活时间比具体的 Activity 实例更长。
| 阶段 | 说明 |
|---|---|
| 创建 | 当 Activity 第一次启动时 |
| 存活 | 当 Activity 因为旋转屏幕而销毁并重新创建时,ViewModel 依然存在 |
| 销毁 | 只有当 Activity 真正彻底结束(调用 finish())或进程被杀掉时,ViewModel 才会调用 onCleared() 并销毁 |
5. 核心准则 (Best Practices)
5.1 禁止持有 Context
⚠️ 绝对不要在 ViewModel 中引用 Activity、Fragment 或 View(会导致内存泄漏)。
如果需要 Context,请继承 AndroidViewModel(application):
kotlin
class MyAndroidViewModel(application: Application) : AndroidViewModel(application) {
private val prefs = application.getSharedPreferences("my_prefs", Context.MODE_PRIVATE)
fun saveData(key: String, value: String) {
prefs.edit().putString(key, value).apply()
}
}
5.2 单向数据流
UI 观察 ViewModel 的状态 → UI 的操作调用 ViewModel 的方法
↓
不要在 UI 中直接修改 ViewModel 的变量
5.3 轻量化
- ViewModel 只负责 逻辑和数据
- ViewModel 不负责 处理复杂的 UI 动画或具体的框架调用
总结
你是正在做传统的 XML 布局开发,还是已经在使用 Jetpack Compose 了?(Compose 中 ViewModel 的注入方式略有不同)。
| 关键点 | 说明 |
|---|---|
| 依赖添加 | lifecycle-viewmodel-ktx + activity-ktx |
| 实例化方式 | by viewModels() 或 ViewModelProvider,禁止 new MyViewModel() |
| 数据管理 | 配合 StateFlow / LiveData 实现响应式 |
| 生命周期 | 跨配置变化存活,真正 finish 时销毁 |
| 最佳实践 | 不持有 Context,单向数据流,轻量化 |