ViewModel 是 Android 架构组件之一,用于管理 UI 相关的数据,并在 配置更改(如屏幕旋转)时保持数据不丢失。
🔹 1. 添加 ViewModel 依赖
在 build.gradle.kts(模块级)中添加:
dependencies {
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2")
}
🔹 2. 创建 ViewModel
(1)基础 ViewModel
import androidx.lifecycle.ViewModel
class CounterViewModel : ViewModel() {
var count = 0 // ViewModel 变量(Activity 重建后不会丢失)
fun increment() {
count++
}
}
🔹 3. 在 Activity/Fragment 中使用
(1)Activity 获取 ViewModel
import android.os.Bundle
import android.widget.TextView
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
private val counterViewModel: CounterViewModel by viewModels() // 通过 viewModels() 获取 ViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val textView: TextView = findViewById(R.id.counterText)
val button: Button = findViewById(R.id.incrementButton)
// 显示当前计数
textView.text = counterViewModel.count.toString()
// 点击按钮增加计数
button.setOnClickListener {
counterViewModel.increment()
textView.text = counterViewModel.count.toString()
}
}
}
✅ 即使旋转屏幕,count 也不会重置。
🔹 4. ViewModel + LiveData 监听数据变化
使用 LiveData,UI 会自动更新:
(1)ViewModel(使用 LiveData)
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class CounterViewModel : ViewModel() {
private val _count = MutableLiveData(0) // 可变 LiveData
val count: LiveData<Int> = _count // 只暴露不可变 LiveData
fun increment() {
_count.value = (_count.value ?: 0) + 1 // 更新数据
}
}
(2)Activity 观察 LiveData
class MainActivity : AppCompatActivity() {
private val counterViewModel: CounterViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val textView: TextView = findViewById(R.id.counterText)
val button: Button = findViewById(R.id.incrementButton)
// 观察 LiveData,自动更新 UI
counterViewModel.count.observe(this) { newCount ->
textView.text = newCount.toString()
}
button.setOnClickListener {
counterViewModel.increment()
}
}
}
✅ LiveData 确保数据变化时,UI 会自动更新。
🔹 5. 处理 ViewModel 依赖(带参数的 ViewModel)
(1)ViewModel 需要参数
如果 ViewModel 需要参数(如 Repository),需要创建 ViewModelProvider.Factory:
class CounterViewModel(private val startValue: Int) : ViewModel() {
private val _count = MutableLiveData(startValue)
val count: LiveData<Int> = _count
fun increment() {
_count.value = (_count.value ?: 0) + 1
}
}
// 自定义 ViewModelFactory
class CounterViewModelFactory(private val startValue: Int) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(CounterViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return CounterViewModel(startValue) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
(2)Activity 获取带参数的 ViewModel
class MainActivity : AppCompatActivity() {
private val counterViewModel: CounterViewModel by viewModels {
CounterViewModelFactory(5) // 传入初始值 5
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val textView: TextView = findViewById(R.id.counterText)
val button: Button = findViewById(R.id.incrementButton)
counterViewModel.count.observe(this) { newCount ->
textView.text = newCount.toString()
}
button.setOnClickListener {
counterViewModel.increment()
}
}
}
✅ 支持带参数的 ViewModel(如从数据库或网络获取初始数据) 。
🔹 6. ViewModel + Room 持久化数据库数据
如果你使用 Room 存储数据,ViewModel 可以直接从 Room 获取 LiveData:
@Dao
interface DiaryDao {
@Query("SELECT * FROM diary_entries ORDER BY date DESC")
fun getAllDiaries(): LiveData<List<DiaryEntry>> // LiveData 监听数据库
}
class DiaryViewModel(private val diaryDao: DiaryDao) : ViewModel() {
val diaryList: LiveData<List<DiaryEntry>> = diaryDao.getAllDiaries()
}
在 Fragment 观察数据:
diaryViewModel.diaryList.observe(viewLifecycleOwner) { diaryList ->
diaryAdapter.submitList(diaryList) // 更新 UI
}
✅ Room + ViewModel + LiveData 确保数据持久化,并自动更新 UI。
🔹 7. ViewModel + Kotlin Flow(协程)
如果你用 Flow,可以这样:
class DiaryViewModel(private val diaryDao: DiaryDao) : ViewModel() {
val diaryListFlow = diaryDao.getAllDiariesFlow()
.stateIn(viewModelScope, SharingStarted.Lazily, emptyList()) // 转为 StateFlow
}
在 Fragment 中 collect 数据:
lifecycleScope.launch {
viewModel.diaryListFlow.collect { diaryList ->
diaryAdapter.submitList(diaryList)
}
}
✅ Flow 更适合复杂数据流(如数据库、网络请求) 。
🔹 8. ViewModel 生命周期
| 场景 | ViewModel 作用 |
|---|---|
| 旋转屏幕 | 保持数据不丢失 |
| App 进后台 | ViewModel 可能被销毁(可用 SavedStateHandle 处理) |
| Fragment 切换 | 共享 ViewModel 以保留数据 |
🔹 总结
✅ ViewModel 用于管理 UI 相关数据,避免因屏幕旋转导致数据丢失。 ✅ 搭配 LiveData 自动通知 UI 变化。 ✅ ViewModel + Room 可以自动监听数据库变化。 ✅ ViewModel + Flow 适合复杂数据流处理。 ✅ ViewModelFactory 用于创建带参数的 ViewModel。