LiveData
本教程共 100 篇 · 第 79 篇 · 更新于 2026-07-28 · 约 7 分钟阅读
79. LiveData
本节目标:理解 LiveData 的生命周期感知特性,会用 MutableLiveData 持有状态、map/switchMap 转换数据,知道 LiveData 和 StateFlow 怎么选。
LiveData 是 Jetpack 早期的可观察数据容器,自带生命周期感知。Compose 时代它被 StateFlow 抢了风头,但老代码、View 体系里还在用,得会。
LiveData 是什么
LiveData 是个「被观察的数据持有者」。和普通变量不同的是,它能让多个观察者订阅变化,并且只在观察者生命周期活跃时才推送更新。
打个比方,LiveData 像订阅的报纸,编辑部(ViewModel)一有新内容就送来。但如果你出门度假(Activity 不可见),送报纸的就先不送,等你回来(Activity 可见)再补上最近一期。
特点:
- 生命周期感知:观察者处于
STARTED或RESUMED才收到更新。 - 自动解绑:观察者的 LifecycleOwner 销毁时自动移除订阅,不会泄漏。
- 不可变 + 可变:
LiveData只读,MutableLiveData可写。 - 主线程通知:更新都在主线程,UI 操作直接来。
基本用法
ViewModel 里持有 MutableLiveData,对外暴露 LiveData:
class NameViewModel : ViewModel() {
private val _name = MutableLiveData<String>()
val name: LiveData<String> = _name
fun setName(newName: String) {
_name.value = newName
}
}
Activity 里观察:
class NameActivity : AppCompatActivity() {
private val viewModel: NameViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_name)
viewModel.name.observe(this) { name ->
nameTextView.text = name
}
button.setOnClickListener {
viewModel.setName("张三")
}
}
}
要点:
observe(this)传this(Activity 是 LifecycleOwner),自动绑生命周期。_name.value = ...在主线程改值,观察者立即收到。- 子线程改值要用
postValue()。
setValue 和 postValue
// 主线程
_name.value = "张三"
// 子线程
_name.postValue("李四")
postValue 切到主线程再发,多个连续调用只保留最后一个。
Warning子线程调
setValue会崩。在协程里改 LiveData 要么withContext(Dispatchers.Main),要么直接用postValue。
LiveData + Room
Room 的 DAO 能直接返回 LiveData:
@Dao
interface NoteDao {
@Query("SELECT * FROM notes")
fun getAll(): LiveData<List<Note>>
}
数据库一变,LiveData 自动推新值。但官方现在更推荐用 Flow,下面会讲。
LiveData + 协程
liveData {} 构建器让 LiveData 和协程配合:
val user: LiveData<User> = liveData {
val data = repo.fetchUser()
emit(data)
}
emit 推一次值。还能配合 emitSource 切换数据源:
val result: LiveData<Result> = liveData {
emit(Result.Loading)
try {
val data = repo.fetch()
emit(Result.Success(data))
} catch (e: Exception) {
emit(Result.Error(e))
}
}
转换:map 和 switchMap
Transformations.map 把一个 LiveData 转成另一个:
val user: LiveData<User> = ...
val userName: LiveData<String> = user.map { "${it.firstName} ${it.lastName}" }
Transformations.switchMap 用于「上游值变了换一个新的 LiveData」:
val userId: MutableLiveData<String> = ...
val user: LiveData<User> = userId.switchMap { id ->
repository.getUser(id) // 返回 LiveData<User>
}
switchMap 适合「输入变了切换数据源」的场景,比如搜索关键词变了换一个查询。
MediatorLiveData 合并多源
MediatorLiveData 能观察多个 LiveData,任一变化都触发:
val mediator = MediatorLiveData<String>()
mediator.addSource(localData) { value ->
mediator.value = "本地:$value"
}
mediator.addSource(remoteData) { value ->
mediator.value = "网络:$value"
}
适合「本地 + 网络合并显示」这种场景。
LiveData vs StateFlow
现代 Android 开发 LiveData 和 StateFlow 怎么选?看这张表:
| 维度 | LiveData | StateFlow |
|---|---|---|
| 生命周期感知 | 内置 | 需要 repeatOnLifecycle 或 collectAsStateWithLifecycle |
| 默认值 | 无 | 必须有 |
| 初始值 | 第一次 setValue 才有 | 构造时就要 |
| 操作符 | 少(map/switchMap) | 多(Flow 全套) |
| 线程 | 主线程 | 可配置 |
| Compose 集成 | observeAsState() | collectAsStateWithLifecycle() |
| 数据层使用 | 不推荐 | 推荐 |
| 老项目兼容 | 好 | - |
官方现在的建议:
- ViewModel 到 UI 这一层:StateFlow 优先,LiveData 也可以。
- 数据层(Repository、DataSource):用 Flow,不要用 LiveData。
- Compose 项目:StateFlow 更顺手。
- View/XML 老项目:LiveData 写起来简洁。
NoteLiveData 不适合数据层,原因是它的转换都在主线程跑,可能卡 UI。Flow 的
flowOn能切线程,灵活得多。
Compose 里用 LiveData
Compose 也能观察 LiveData:
@Composable
fun NameScreen(viewModel: NameViewModel = viewModel()) {
val name by viewModel.name.observeAsState(initial = "")
Text("名字:$name")
}
observeAsState 来自 runtime-livedata 库。但新项目建议直接用 StateFlow + collectAsStateWithLifecycle。
Flow 转 LiveData
老项目迁移时,Repository 返回 Flow,ViewModel 转 LiveData 暴露给 View:
class MyViewModel(repo: MyRepository) : ViewModel() {
val data: LiveData<List<Item>> = repo.observeItems()
.asLiveData(viewModelScope.coroutineContext)
}
或者:
val data: LiveData<List<Item>> = repo.observeItems().asLiveData()
Tip迁移策略:数据层先换 Flow,ViewModel 暴露层可以暂时保持 LiveData 兼容老 UI,UI 改 Compose 时再换 StateFlow。
LiveData 的扩展
自定义 LiveData 可以重写 onActive() 和 onInactive():
class LocationLiveData(private val ctx: Context) : LiveData<Location>() {
private val manager = ctx.getSystemService(LocationManager::class.java)
override fun onActive() {
// 有观察者了,开始定位
manager.requestLocationUpdates(listener)
}
override fun onInactive() {
// 没观察者了,停止定位省电
manager.removeUpdates(listener)
}
}
onActive 在第一个观察者订阅时调用,onInactive 在最后一个观察者解绑时调用。适合「按需启动/停止」的资源。
常见坑
- Fragment 用
this观察:Fragment 视图销毁后还在收,崩。用viewLifecycleOwner。 - 子线程调 setValue:崩。用
postValue。 - LiveData 放 Repository:转换在主线程,可能卡 UI。用 Flow。
- LiveData 装一次性事件:旋转屏幕重复触发。用 SingleLiveEvent 或者 SharedFlow。
- observeForever 忘记 remove:泄漏。一般用
observe(lifecycleOwner)。 - switchMap 漏写:直接调
repository.getUser(id)返回 LiveData 但不订阅,没数据。
小结
LiveData 是生命周期感知的可观察数据容器,适合 ViewModel 到 UI 这一层。MutableLiveData 持有可变状态,map/switchMap 转换,MediatorLiveData 合并多源。数据层用 Flow,UI 层 LiveData 或 StateFlow 都行,新项目优先 StateFlow。
下一章讲 Lifecycle 组件,看怎么让普通类也能感知生命周期。