一、ViewModel 概述
ViewModel 是 Android Jetpack 架构组件中的重要一员,专门为解决 Activity 和 Fragment 中的 UI 数据管理问题而设计。它的核心目标是:
-
管理 UI 相关数据:以生命周期感知的方式保存和管理数据
-
解决配置变更问题:在屏幕旋转等配置更改时保留数据
-
避免内存泄漏:自动清理资源,防止 Activity/Fragment 引用泄漏
// 基本ViewModel类定义 class MyViewModel : ViewModel() { // 数据将在此保存 var counter = 0 }
二、ViewModel 生命周期
理解 ViewModel 的生命周期是其正确使用的关键:

-
ViewModel 的生命周期比创建它的 Activity/Fragment 更长
-
在 Activity 完成(finish)时才会清除
-
屏幕旋转等配置变化不会导致重建
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 获取ViewModel实例 val model: MyViewModel by viewModels() } }
三、ViewModel 的基本使用
1. 添加依赖
首先在 build.gradle 中添加依赖:
dependencies { implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2" // 如果使用ViewModel带SavedState implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.2" }
2. 创建 ViewModel 类
class UserViewModel : ViewModel() { private val _users = MutableLiveData<List<User>>() val users: LiveData<List<User>> = _users init { loadUsers() } private fun loadUsers() { // 模拟数据加载 _users.value = listOf(User("张三"), User("李四")) } }
3. 在 Activity/Fragment 中使用
class UserActivity : AppCompatActivity() {
private val userViewModel: UserViewModel by viewModels()override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_user) userViewModel.users.observe(this) { users -> // 更新UI updateUserList(users) } }
}
四、ViewModel 的高级特性
1. ViewModel 带参数
如果需要传递参数给 ViewModel,可以使用 ViewModelProvider.Factory:
class UserViewModel(private val userId: String) : ViewModel() {
// ...
}
class UserViewModelFactory(private val userId: String) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return UserViewModel(userId) as T
}
}
// 使用
val factory = UserViewModelFactory("123")
val viewModel = ViewModelProvider(this, factory).get(UserViewModel::class.java)
2. SavedStateHandle
处理进程死亡后恢复数据:
class SavedStateViewModel(private val state: SavedStateHandle) : ViewModel() {
val counter: LiveData<Int> = state.getLiveData("counter", 0)
fun increment() {
state["counter"] = (counter.value ?: 0) + 1
}
}
3. 在 Fragment 间共享数据
class SharedViewModel : ViewModel() {
val selectedItem = MutableLiveData<Item>()
fun select(item: Item) {
selectedItem.value = item
}
}
// FragmentA
val model: SharedViewModel by activityViewModels()
// FragmentB
val model: SharedViewModel by activityViewModels()
五、ViewModel 最佳实践
随着 Jetpack 组件的不断演进,ViewModel 也在持续增强功能(如与 Hilt 的集成、更完善的状态保存机制等),值得开发者持续关注和学习。
-
职责单一:每个 ViewModel 应只负责一个屏幕或功能模块
-
避免引用 Context:ViewModel 不应持有 Activity/Fragment 的引用
-
合理使用 LiveData:暴露不可变的 LiveData,内部使用 MutableLiveData
-
结合 Repository:数据操作应委托给 Repository 层
-
测试友好:ViewModel 应易于单元测试
// 良好结构的ViewModel示例 class OrderViewModel( private val orderRepository: OrderRepository, private val savedStateHandle: SavedStateHandle ) : ViewModel() { private val _order = MutableLiveData<Order>() val order: LiveData<Order> = _order private val _loading = MutableLiveData<Boolean>() val loading: LiveData<Boolean> = _loading fun loadOrder(orderId: String) { _loading.value = true viewModelScope.launch { try { _order.value = orderRepository.getOrder(orderId) } catch (e: Exception) { // 处理错误 } finally { _loading.value = false } } } }
六、常见问题与解决方案
1. ViewModel 内存泄漏
问题 :在 ViewModel 中持有 Activity/Fragment 引用
解决:使用 Application Context 或完全避免 Context2. 数据重复加载
问题 :每次配置变更都重新加载数据
解决:在 ViewModel 中缓存数据class MyViewModel : ViewModel() { private var cachedData: List<Data>? = null fun getData(): LiveData<List<Data>> { if (cachedData == null) { loadData() } return Transformations.map(_source) { it } } }
3. 测试困难
解决:依赖注入和接口抽象
class MyViewModel( private val dataSource: DataSourceInterface ) : ViewModel() { // ... } // 测试时可以传入Mock实现
七、ViewModel 与协程
ViewModel 内置了 viewModelScope,便于协程管理:
class CoroutineViewModel : ViewModel() { fun fetchData() { viewModelScope.launch { try { val data = repository.fetchData() _uiState.value = UiState.Success(data) } catch (e: Exception) { _uiState.value = UiState.Error(e) } } } }
结语
ViewModel 是现代 Android 开发中不可或缺的架构组件,它优雅地解决了 UI 控制器(Activity/Fragment)中数据管理的难题。通过合理使用 ViewModel,开发者可以:
-
构建更健壮、更易维护的应用程序
-
提高代码的可测试性
-
减少内存泄漏的风险
-
提供更好的用户体验