1. LiveData与Flow基础概念:生命周期感知、冷流热流区别、观察者模式
观察任务进度的本质是数据变化→观察者接收通知。Android 开发中,LiveData 和 Flow 是两种主流通用观察者机制,但设计目标与使用场景差异显著。本章从观察者模式出发,拆解生命周期感知与冷流/热流两大核心区别,为后续任务进度观察实现打下理论基础。
1.1 观察者模式——两者共同的根
无论是 LiveData 还是 Flow,底层都遵循观察者模式:一个被观察对象(数据源)维护一组依赖者(观察者),当数据变更时自动通知所有观察者。
| 特性 | LiveData 观察者 | Flow 观察者 |
|---|---|---|
| 订阅方式 | observe(LifecycleOwner, Observer) | .collect { } / .launchIn(scope) |
| 通知时机 | 主线程,自动 | 协程调度器控制 |
| 取消订阅 | 自动(生命周期绑定) | 手动或通过协程取消 |
比较: LiveData 专为 Android UI 层设计,自动处理生命周期;Flow 是 Kotlin 协程原语,更灵活,可用于非 UI 层。
1.2 LiveData:生命周期感知的观察者
LiveData 的核心价值在于自动感知 Activity/Fragment 生命周期,避免内存泄漏和空指针。当 LifecycleOwner 处于 STARTED 状态时订阅才会生效,在 DESTROYED 状态自动移除观察者。
// LiveData 基本使用 – ViewModel 层
class ProgressViewModel : ViewModel() {
private val _progress = MutableLiveData<Int>(0)
val progress: LiveData<Int> get() = _progress
fun startTask() {
viewModelScope.launch {
for (i in 0..100 step 10) {
delay(500)
_progress.postValue(i) // 主线程安全更新
}
}
}
}
// Activity 层 – 自动感知生命周期
viewModel.progress.observe(this) { value ->
progressBar.progress = value
}
常见错误: 在非 UI 线程调用
setValue() 会崩溃,必须使用 postValue()。若多次快速 postValue,只有最后一个值被传递,中间值可能丢失。
1.3 Flow:冷流与热流的分野
Flow 遵循冷流设计——每次订阅都重新执行上游生产者代码。与之相对,StateFlow 和 SharedFlow 是热流——数据独立于订阅者存在,多个订阅者共享同一数据流。
| 对比维度 | 冷流(Flow) | 热流(StateFlow / SharedFlow) |
|---|---|---|
| 生产者启动时机 | 每次 collect 时重新启动 | 生产者独立启动,订阅者不影响 |
| 数据缓存 | 无,仅当前发射 | StateFlow 缓存最新值,SharedFlow 可配置 replay |
| 生命周期感知 | 需配合 repeatOnLifecycle | 同 Flow,但 StateFlow 常用于 UI 层 |
| 典型场景 | 网络请求、数据库查询 | UI 状态管理、事件总线 |
// 冷流 Flow – 每次 collect 执行网络请求
fun fetchProgress(): Flow<Int> = flow {
emit(0)
delay(500)
emit(50)
delay(500)
emit(100)
}.flowOn(Dispatchers.IO) // 指定生产协程
// collect 时才开始执行
scope.launch {
fetchProgress().collect { progress ->
updateUI(progress)
}
}
// 热流 StateFlow – 一直持有最新状态
private val _uiState = MutableStateFlow<Int>(0)
val uiState: StateFlow<Int> get() = _uiState
// 更新状态
_uiState.value = newProgress
// 任意订阅者立即拿到最新值
scope.launch {
uiState.collect { progress ->
// 自动接收新值和当前值
}
}
工程建议: 在 UI 层观察任务进度首选
StateFlow + repeatOnLifecycle,既享受生命周期安全,又避免 LiveData 限制(如无法使用协程、无法区分数据是否“已消耗”)。
1.4 核心概念关系图
下图从观察者模式出发,梳理 LiveData 与 Flow 家族的关系,突出生命周期感知与冷/热流差异。
1.5 调试与性能提示
- 调试 LiveData: 在
observe回调中加入日志,注意 postValue 的背压丢失问题;使用observeForever需手动removeObserver。 - 调试 Flow: 使用
.catch { }处理异常,.onEach { }添加日志,避免在收集时 block 过久。 - 性能对比: LiveData 仅用于 UI 层时开销极低;Flow 在非阻塞协程场景下线程切换更精细,适合复杂数据流。