ViewModel + LiveData 教程:构建响应式 Android 应用

ViewModel + LiveData 教程:构建响应式 Android 应用

ViewModelLiveData 是 Android Jetpack 架构组件的核心模块,用于构建响应式生命周期安全的现代 Android 应用。以下是完整实现指南:


📌 核心概念

组件 作用
ViewModel 以生命周期感知方式管理 UI 数据,界面旋转时数据不丢失
LiveData 可观察的数据容器,仅在 Activity/Fragment 处于活跃状态时更新 UI
优势 ✅ 避免内存泄漏 ✅ 自动更新 UI ✅ 数据持久化 ⚡️ 响应式编程

🛠️ 配置 Gradle

首先在 app/build.gradle 添加依赖:

bash 复制代码
dependencies {
    def lifecycle_version = "2.6.2"
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
}

🧩 步骤 1: 创建 ViewModel

kotlin 复制代码
// CounterViewModel.kt
import androidx.lifecycle.ViewModel
import androidx.lifecycle.MutableLiveData

class CounterViewModel : ViewModel() {
    // MutableLiveData 用于修改数据,对外暴露不可变 LiveData
    private val _counter = MutableLiveData(0)
    val counter: LiveData<Int> get() = _counter
    
    // 在后台线程模拟耗时操作
    fun increment() {
        viewModelScope.launch(Dispatchers.Default) {
            delay(1000) // 模拟耗时操作
            _counter.postValue(_counter.value?.plus(1))
        }
    }
    
    // 普通数据操作(无耗时)
    fun reset() {
        _counter.value = 0
    }
}

🖼 步骤 2: 在 Activity/Fragment 中使用

kotlin 复制代码
// MainActivity.kt
class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private val viewModel: CounterViewModel by viewModels() // 委托初始化

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // 监听 LiveData 变化(仅当 Activity 处于 STARTED/RESUMED 状态时触发)
        viewModel.counter.observe(this) { count ->
            binding.tvCount.text = "Count: $count"
            binding.progressBar.visibility = if (count > 5) View.VISIBLE else View.GONE
        }

        binding.btnIncrement.setOnClickListener {
            viewModel.increment()
        }

        binding.btnReset.setOnClickListener {
            viewModel.reset()
        }
    }
}

📐 布局文件 (activity_main.xml)

ini 复制代码
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tvCount"
        android:text="Count: 0"
        android:textSize="24sp"/>

    <ProgressBar
        android:id="@+id/progressBar"
        android:visibility="gone" />

    <Button
        android:id="@+id/btnIncrement"
        android:text="Increment after delay"/>
        
    <Button
        android:id="@+id/btnReset"
        android:text="Reset"/>

</LinearLayout>

⚡ 高级用法

1. 数据转换 (Transformations)

kotlin 复制代码
class UserViewModel : ViewModel() {
    private val _userId = MutableLiveData("")
    val userName: LiveData<String> = Transformations.map(_userId) { id ->
        repository.getUserName(id) // 将用户ID转换成用户名
    }
}

2. 多 Fragment 共享数据

csharp 复制代码
// 在 Fragment 中共享同一个 ViewModel
val sharedViewModel: SharedViewModel by activityViewModels()

3. 结合 Room 数据库

kotlin 复制代码
@Dao
interface UserDao {
    @Query("SELECT * FROM users")
    fun getAllUsers(): LiveData<List<User>> // Room 原生支持 LiveData
}

// ViewModel 中直接暴露查询结果
val users: LiveData<List<User>> = userDao.getAllUsers()

🚫 常见错误及解决方案

问题 解决方案
直接在 LiveData 中更新 UI 通过观察者模式更新,避免在 ViewModel 操作 UI
忘记调用 observe() 确保所有 LiveData 都被观察
后台线程错误使用 .value= postValue() 从非 UI 线程更新
ViewModel 持有 Context 引用 使用 AndroidViewModel + Application 上下文

🔐 生命周期安全原理

  1. ViewModel 通过 ViewModelStore 在配置更改时存活
  2. LiveData 自动取消订阅非活跃状态组件
  3. viewModelScopeonCleared() 自动取消协程

💡 最佳实践

  1. 职责分离:ViewModel 只负责数据处理,不涉及 UI 逻辑
  2. 单向数据流:View → ViewModel → Repository → DataSource
  3. 状态管理 :使用 StateFlowMediatorLiveData 合并多个数据源
  4. 测试:独立测试 ViewModel 和 LiveData(无需 Android 依赖)

掌握 ViewModel + LiveData 可大幅提升应用稳定性与响应效率!建议结合 Data BindingKotlin Flow 构建更现代化的解决方案。

相关推荐
野生的码农9 小时前
放过自己,降低预期,及时行乐
android·ai编程
huwuhang9 小时前
索尼PS3游戏合集【中文游戏】8.12T 1430个游戏+PS3模拟器
android·游戏·智能手机·游戏机·电视
Grackers11 小时前
Android Perfetto 系列 5:Android App 基于 Choreographer 的渲染流程
android
踩着两条虫11 小时前
AI驱动的Vue3应用开发平台深入探究(十):物料系统之内置组件库
android·前端·vue.js·人工智能·低代码·系统架构·rxjava
sam.li12 小时前
JADX MCP 原理与使用部署
android·逆向·jadx
冬奇Lab12 小时前
Android 15音频子系统(五):AudioPolicyService策略管理深度解析
android·音视频开发·源码阅读
亚历克斯神12 小时前
Flutter for OpenHarmony: Flutter 三方库 mutex 为鸿蒙异步任务提供可靠的临界资源互斥锁(并发安全基石)
android·数据库·安全·flutter·华为·harmonyos
dalancon14 小时前
SurfaceControl 的事务提交给 SurfaceFlinger,以及 SurfaceFlinger 如何将这些数据设置到对应 Layer 的完整流程
android
dalancon14 小时前
SurfaceFlinger Layer 到 HWC 通信流程详解
android
cccccc语言我来了14 小时前
Linux(9)操作系统
android·java·linux