一文读懂 LiveData

7 阅读4分钟

概述

LiveData 能够感知与其关联的 LifecycleOwner (如 Activity、Fragment) 的生命周期,仅当 LifecycleOwner 处于started 或 resumed 状态时,LiveData 才会通知观察者数据的变化,避免无效的 UI 更新

原理

LiveData 核心是关联 LifecycleOwner(Activity/Fragment)的生命周期:LiveData 内部会向 LifecycleOwner 注册 LifecycleEventObserver,监听其生命周期状态变化;当宿主生命周期状态为 destroyed 时,LiveData 会自动移除观察者,无需手动处理,还从根源避免内存泄漏

LiveData 核心源码

// LiveData 内部的生命周期绑定观察者(核心内部类)
private class LifecycleBoundObserver(
    val lifecycleOwner: LifecycleOwner,
    val observer: Observer<in T>
) : Observer<T>, LifecycleEventObserver {

    // 监听生命周期事件变化
    override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
        val currentState = source.lifecycle.currentState
        // 核心1:如果宿主已销毁(DESTROYED),自动移除观察者
        if (currentState == Lifecycle.State.DESTROYED) {
            removeObserver(observer) // 自动解绑,避免内存泄漏
            return
        }
        
        // 核心2:判断宿主是否处于活跃状态(STARTED/RESUMED)
        var prevState: Lifecycle.State? = null
        if (prevState != currentState) {
            val isActive = currentState.isAtLeast(Lifecycle.State.STARTED)
            // 更新观察者的活跃状态
            activeStateChanged(isActive)
        }
    }

    // 数据变更时的回调(仅当活跃时才触发)
    override fun onChanged(t: T) {
        if (isActive) { // isActive 由上面的生命周期状态决定
            observer.onChanged(t) // 通知外部观察者
        } else {
            // 非活跃状态:暂存数据(粘性事件的基础),等活跃后再通知
            pendingData = t
        }
    }
}

关键方法对比(核心重点)

方法使用线程特点适用场景
setValue(T value)必须主线程同步更新数据,立即通知观察者主线程中修改数据(如按钮点击、UI 交互、实时状态变更)
postValue(T value)可子线程 / 主线程异步更新数据(通过 Handler 切主线程),若多次调用仅最后一次生效子线程中修改数据(如网络请求、数据库查询后更新数据)

优点(核心价值)

  1. ✅ 生命周期感知能力:自动适应 UI 组件的生命周期,避免在组件不可见时执行不必要的数据更新操作,降低性能消耗
  2. ✅ 线程安全能力:适配多线程场景,setValue 保证主线程安全postValue 自动切主线程,避免 UI 线程异常崩溃。
  3. ✅ 无内存泄漏问题:宿主销毁时自动解绑观察者,彻底避免 Activity/Fragment 泄漏;数据释放与 ViewModel 生命周期强绑定,资源回收更高效。

应用(计数器示例)

以一个简单的计数器为例,实现MVVM 架构下的单向数据流

ViewModel(核心:解耦 View 与数据,封装业务逻辑)

处理业务逻辑,持有可观察数据,与 View 解耦,无需持有任何 View 引用,即使 activity 销毁,viewmodel 数据仍保留

// 自定义 ViewModel,存放计数器数据
class CounterViewModel : ViewModel() {
    // 1. MutableLiveData:可变的 LiveData(可修改值),仅在 ViewModel 内部使用,**[开闭原则]**
    private val _counter = MutableLiveData<Int>(0)

    // 2. LiveData:不可变的暴露给外部(只读),**保证数据安全**,避免外部随意改值
    val counter: LiveData<Int> = _counter

    // 3. 提供修改数据的方法(外部通过调用方法更新,而非直接改值)
    fun incrementCounter() {
        // 获取当前值(为空则默认 0),+1 后更新
        _counter.value = (_counter.value ?: 0) + 1
    }
}

View(核心:仅负责 UI 展示与用户交互,不处理业务逻辑)

show UI、接收用户交互,不处理业务数据逻辑,通过 observe 监听 viewmodel 的 livedata 刷新 UI

class CounterActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // 获取 viewmodel(生命周期独立,配置变更不丢失)
        val viewModel = ViewModelProvider(this)[CounterViewModel::class.java]

        // 绑定控件
        val tvCounter = findViewById<TextView>(R.id.tv_counter)
        val btnAdd = findViewById<Button>(R.id.btn_add)

        // 观察Livedata变化(生命周期感知,自动解绑)
        viewModel.counter.observe(this) { newCount ->
            tvCounter.text = "当前计数:$newCount"
        }

        // 接收用户交互,调用ViewModel方法修改数据
        btnAdd.setOnClickListener {
            viewModel.incrementCounter()
        }
    }
}

LiveData 粘性事件(核心特性)

LiveData 存在粘性事件特性:若 LiveData 先发送了数据,之后再注册观察者,观察者仍能收到这条历史数据

✅ 场景示例:ViewModel 中先请求网络数据并更新 LiveData,此时 Activity 还未创建;Activity 创建后观察 LiveData,仍能收到网络请求的结果,无需重新请求。

⚠️ 注意:若不需要粘性事件(如单次事件传递),需自定义 LiveData 屏蔽该特性(如使用 SingleLiveEventEventWrapper)。

核心总结

  1. 生命周期感知是 LiveData 的核心基础,仅活跃状态下通知 UI 更新,兼顾性能与体验;
  2. setValue/postValue 是线程安全的核心,需严格匹配使用线程,避免崩溃;
  3. 私有 MutableLiveData + 暴露只读 LiveData 是数据安全的最佳实践,符合 MVVM 单向数据流规范;
  4. 粘性事件是 LiveData 的默认特性,需根据业务场景选择是否启用。