ViewModel #
一、ViewModel概述 #
ViewModel是Jetpack架构组件之一,用于存储和管理UI相关数据。ViewModel在配置更改(如屏幕旋转)时不会销毁,确保数据不会丢失。
1.1 ViewModel的特点 #
- 生命周期感知
- 配置更改时数据保留
- 避免内存泄漏
- 与UI解耦
1.2 ViewModel生命周期 #
text
Activity创建
│
▼
ViewModel创建
│
▼
Activity运行中(ViewModel保持)
│
├── 屏幕旋转 ──► Activity重建,ViewModel保持
│
▼
Activity销毁
│
▼
ViewModel的onCleared()调用
│
▼
ViewModel销毁
二、基本使用 #
2.1 添加依赖 #
kotlin
dependencies {
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0")
}
2.2 创建ViewModel #
kotlin
class MainViewModel : ViewModel() {
private val _count = MutableLiveData<Int>()
val count: LiveData<Int> = _count
init {
_count.value = 0
}
fun increment() {
_count.value = (_count.value ?: 0) + 1
}
fun decrement() {
_count.value = (_count.value ?: 0) - 1
}
override fun onCleared() {
super.onCleared()
// 清理资源
}
}
2.3 在Activity中使用 #
kotlin
class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel.count.observe(this) { count ->
binding.tvCount.text = count.toString()
}
binding.btnIncrement.setOnClickListener {
viewModel.increment()
}
}
}
2.4 在Fragment中使用 #
kotlin
class MainFragment : Fragment() {
private val viewModel: MainViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.count.observe(viewLifecycleOwner) { count ->
binding.tvCount.text = count.toString()
}
}
}
三、AndroidViewModel #
当需要在ViewModel中使用Application Context时,使用AndroidViewModel。
kotlin
class MyViewModel(application: Application) : AndroidViewModel(application) {
private val context = getApplication<Application>()
fun getResourceString(resId: Int): String {
return context.getString(resId)
}
}
// 使用
class MainActivity : AppCompatActivity() {
private val viewModel: MyViewModel by viewModels()
}
四、ViewModel与Repository #
4.1 创建Repository #
kotlin
class UserRepository(
private val apiService: ApiService,
private val userDao: UserDao
) {
fun getUsers(): Flow<List<User>> = flow {
// 先返回缓存数据
emit(userDao.getAll())
// 从网络获取数据
val remoteUsers = apiService.getUsers()
// 保存到数据库
userDao.insertAll(remoteUsers)
// 返回最新数据
emit(remoteUsers)
}
.catch { e ->
emit(userDao.getAll())
}
}
4.2 在ViewModel中使用Repository #
kotlin
class UserViewModel(
private val repository: UserRepository
) : ViewModel() {
private val _users = MutableLiveData<List<User>>()
val users: LiveData<List<User>> = _users
private val _loading = MutableLiveData<Boolean>()
val loading: LiveData<Boolean> = _loading
private val _error = MutableLiveData<String>()
val error: LiveData<String> = _error
fun loadUsers() {
viewModelScope.launch {
_loading.value = true
try {
repository.getUsers()
.collect { users ->
_users.value = users
}
} catch (e: Exception) {
_error.value = e.message
} finally {
_loading.value = false
}
}
}
}
五、Fragment间共享数据 #
5.1 使用activityViewModels #
kotlin
class MasterFragment : Fragment() {
private val viewModel: SharedViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewModel.selectedItem.observe(viewLifecycleOwner) { item ->
// 更新UI
}
}
}
class DetailFragment : Fragment() {
private val viewModel: SharedViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewModel.selectedItem.observe(viewLifecycleOwner) { item ->
// 显示详情
}
}
}
class SharedViewModel : ViewModel() {
private val _selectedItem = MutableLiveData<Item>()
val selectedItem: LiveData<Item> = _selectedItem
fun selectItem(item: Item) {
_selectedItem.value = item
}
}
六、SavedStateHandle #
SavedStateHandle用于保存与恢复数据,即使进程被杀死也能恢复。
kotlin
class DetailViewModel(
savedStateHandle: SavedStateHandle
) : ViewModel() {
private val itemId = savedStateHandle.get<String>("itemId")
private val _item = MutableLiveData<Item>()
val item: LiveData<Item> = _item
init {
loadItem()
}
private fun loadItem() {
viewModelScope.launch {
// 使用itemId加载数据
}
}
}
// 传递参数
class MainActivity : AppCompatActivity() {
private val viewModel: DetailViewModel by viewModels {
val itemId = intent.getStringExtra("itemId")
DetailViewModel.Factory(itemId)
}
}
// 或使用SavedStateViewModelFactory
class DetailViewModel(
savedStateHandle: SavedStateHandle,
private val repository: ItemRepository
) : ViewModel() {
companion object {
const val ITEM_ID_KEY = "itemId"
}
val itemId: String? = savedStateHandle[ITEM_ID_KEY]
class Factory(
private val itemId: String,
private val repository: ItemRepository
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
val savedStateHandle = SavedStateHandle()
savedStateHandle[ITEM_ID_KEY] = itemId
return DetailViewModel(savedStateHandle, repository) as T
}
}
}
七、ViewModel与依赖注入 #
7.1 使用Hilt #
kotlin
@HiltViewModel
class MainViewModel @Inject constructor(
private val repository: UserRepository
) : ViewModel() {
private val _users = MutableLiveData<List<User>>()
val users: LiveData<List<User>> = _users
fun loadUsers() {
viewModelScope.launch {
_users.value = repository.getUsers()
}
}
}
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels()
}
7.2 使用ViewModelFactory #
kotlin
class MainViewModelFactory(
private val repository: UserRepository
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(MainViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return MainViewModel(repository) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels {
MainViewModelFactory(UserRepository())
}
}
八、最佳实践 #
8.1 避免在ViewModel中持有View引用 #
kotlin
// 错误
class MyViewModel(private val view: View) : ViewModel()
// 正确
class MyViewModel : ViewModel() {
private val _data = MutableLiveData<String>()
val data: LiveData<String> = _data
}
8.2 使用协程处理异步操作 #
kotlin
class MainViewModel : ViewModel() {
private val _result = MutableLiveData<Result<Data>>()
val result: LiveData<Result<Data>> = _result
fun fetchData() {
viewModelScope.launch {
_result.value = Result.loading()
try {
val data = repository.getData()
_result.value = Result.success(data)
} catch (e: Exception) {
_result.value = Result.error(e.message)
}
}
}
}
8.3 使用Flow替代LiveData #
kotlin
class MainViewModel : ViewModel() {
// 使用StateFlow替代LiveData
private val _uiState = MutableStateFlow<UiState>(UiState.Loading)
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
fun loadData() {
viewModelScope.launch {
repository.getData()
.catch { e ->
_uiState.value = UiState.Error(e.message)
}
.collect { data ->
_uiState.value = UiState.Success(data)
}
}
}
}
// 在Activity中观察
lifecycleScope.launch {
viewModel.uiState.collect { state ->
when (state) {
is UiState.Loading -> showLoading()
is UiState.Success -> showData(state.data)
is UiState.Error -> showError(state.message)
}
}
}
九、总结 #
本章详细介绍了ViewModel:
- ViewModel的基本概念和生命周期
- ViewModel的创建和使用
- AndroidViewModel的使用
- ViewModel与Repository配合
- Fragment间共享数据
- SavedStateHandle的使用
- 依赖注入配置
- 最佳实践
ViewModel是Android架构组件的核心,合理使用可以提高代码质量和可维护性。
最后更新:2026-03-26