一、从问题出发

场景:点赞数变了,界面要更新

假设有一个点赞按钮,后面有个数字显示点赞数:

class VideoActivity : Activity() {
 
    var likeCount = 0
    lateinit var likeTextView: TextView
 
    fun onLikeButtonClick() {
        likeCount = likeCount + 1
        likeTextView.text = "$likeCount"   // 数据变了,手动刷新界面
    }
}

看起来没问题。但实际场景中,点赞数可能从很多地方变化:

// 用户点了赞
fun onLikeButtonClick() {
    likeCount = likeCount + 1
    likeTextView.text = "$likeCount"   // 要记得刷新
}
 
// 网络请求回来了,服务端告诉你真实数量
fun onNetworkResponse(count: Int) {
    likeCount = count
    likeTextView.text = "$likeCount"   // 又要记得刷新
}
 
// 从其他页面返回,数据同步了
fun onSyncData(count: Int) {
    likeCount = count
    likeTextView.text = "$likeCount"   // 还要记得刷新
}

问题:每次改数据,都要手动刷新界面。漏了一处就是 bug。

二、LiveData 是什么

LiveData 的核心思路:你只管改数据,界面自动更新。

// LiveData 就是一个"可以被观察的数据容器"
val likeCount = MutableLiveData<Int>(0)
//              ^^^^^^^^^^^^^^^^^^^^^^
//              不是普通的 Int,而是一个"可被观察的 Int"

一句话定义:LiveData = 可观察的数据容器 + 自动感知生命周期。

三、LiveData 基本用法

分两步:

第一步:观察数据(一般在 onCreate 里做一次)

override fun onCreate() {
    // 告诉 LiveData:"你的值变了就通知我"
    likeCount.observe(this) { newValue ->
        // 这个回调会在数据变化时自动执行
        likeTextView.text = "$newValue"
    }
}

第二步:改数据(任何地方,任何时候)

// 用户点赞
fun onLikeButtonClick() {
    likeCount.value = likeCount.value!! + 1    // 只管改数据
    // 不用手动刷新界面,LiveData 会自动通知 observe 里的回调
}
 
// 网络返回
fun onNetworkResponse(count: Int) {
    likeCount.value = count    // 只管改数据
    // 界面自动更新
}
 
// 数据同步
fun onSyncData(count: Int) {
    likeCount.value = count    // 只管改数据
    // 界面自动更新
}

不管从哪里改 likeCount.valueobserve** 里注册的回调都会自动执行。**

四、对比:有 LiveData vs 没有 LiveData

没有 LiveData

var likeCount = 0
 
改数据的地方A:  likeCount = 1;  textView.text = "$likeCount"  // 手动刷
改数据的地方B:  likeCount = 2;  textView.text = "$likeCount"  // 手动刷
改数据的地方C:  likeCount = 3;  textView.text = "$likeCount"  // 手动刷
(漏一处就是 bug)

有 LiveData

val likeCount = MutableLiveData(0)
 
注册一次:      likeCount.observe { textView.text = "$it" }
改数据的地方A:  likeCount.value = 1    // 界面自动更新
改数据的地方B:  likeCount.value = 2    // 界面自动更新
改数据的地方C:  likeCount.value = 3    // 界面自动更新
(不可能漏)

五、LiveData 的生命周期感知能力

这是 LiveData 相比普通回调/EventBus 的核心优势

注意observe的第一个参数:

likeCount.observe(this) { newValue ->
//                ^^^^
//                this 就是 LifecycleOwner(Activity)
    likeTextView.text = "$newValue"
}

传了this(Activity)之后,LiveData 会自动判断

页面状态LiveData 行为
页面可见(RESUMED)数据变了就通知
页面不可见(STOPPED)数据变了先不通知,等页面回来再通知
页面销毁(DESTROYED)自动取消观察,不会内存泄漏

具体流程示例

用户在看页面  →  likeCount.value = 5  →  立刻回调,界面刷新
用户按了Home  →  likeCount.value = 8  →  不回调(页面不可见,刷了也没用)
用户切回来    →  自动用最新值 8 回调一次  →  界面刷新
用户关了页面  →  自动取消观察,不用手动清理

六、Lifecycle Observer 回顾

LiveData 的生命周期感知能力,底层依赖的就是 Lifecycle + Observer 机制。

Lifecycle Observer 做的事:观察”页面状态”变化

Lifecycle + Observer  →  观察"页面状态"变化
                         页面 onResume 了 → 通知我
                         页面 onPause 了  → 通知我

LiveData 做的事:观察”数据”变化

LiveData + observe    →  观察"数据"变化
                         点赞数变了 → 通知我
                         评论数变了 → 通知我
                         而且页面不可见时自动暂停通知

LiveData 把 Lifecycle(页面状态感知)和数据观察结合在了一起。

七、MutableLiveData vs LiveData

类型可读可写使用场景
LiveData<T>getValue()不可写对外暴露,只允许观察
MutableLiveData<T>getValue()setValue() / postValue()内部使用,允许修改

常见模式:ViewModel 内部用 MutableLiveData,对外暴露 LiveData

class VideoViewModel : ViewModel() {
    // 内部可写
    private val _likeCount = MutableLiveData(0)
    // 外部只读
    val likeCount: LiveData<Int> = _likeCount
 
    fun like() {
        _likeCount.value = _likeCount.value!! + 1
    }
}

八、setValue() vs postValue()

方法线程要求说明
setValue(value)必须在主线程调用同步设置,立即通知观察者
postValue(value)可以在任意线程调用异步 post 到主线程后再通知
// 主线程中
likeCount.value = 5              // OK,用 setValue
 
// 子线程 / 网络回调中
likeCount.postValue(5)           // OK,用 postValue

九、总结

┌──────────────────────────────────────────────────┐
│              传统做法                             │
│  数据变了 → 手动找到所有 UI → 逐个刷新                │
│  (容易遗漏,容易内存泄漏)                          │
└──────────────────────────────────────────────────┘
                     ↓ 演进为
┌──────────────────────────────────────────────────┐
│              LiveData                            │
│  数据变了 → 自动通知所有观察者 → UI 自动刷新           │
│  页面不可见 → 自动暂停通知                           │
│  页面销毁   → 自动取消观察                          │
│  (不会遗漏,不会泄漏)                              │
└──────────────────────────────────────────────────┘

核心要点:

  1. LiveData 是可观察的数据容器 —— 数据变了自动通知
  2. 感知生命周期 —— 页面不可见不通知,页面销毁自动清理
  3. 数据驱动 UI —— 改数据就行,不用操心界面刷新
  4. 结合 ViewModel 使用 —— ViewModel 持有 LiveData,Activity/Fragment 观察它

更新: 2026-03-08 14:22:13
原文: https://www.yuque.com/dongpozhouzi-mshe3/zhm85g/swe9n9ygui5wf2l8


相关笔记