1. StateFlow与SharedFlow概念总览

StateFlow和SharedFlow是Kotlin协程中热数据流(hot Flow)的两个关键实现,用于在组件之间安全、高效地传递状态或事件。它们都基于kotlinx.coroutines.flow构建,提供了比LiveData更灵活、更协程原生的数据共享方案。本章从概念、用途、与LiveData的对比以及必要的协程基础入手,为后续章节的深入实现打下根基。

1.1 定义与核心特性

特性StateFlowSharedFlow
类型有状态的热流(持有最新值)无状态热流(可通过配置持有重放值)
用途状态持有与观察(类似LiveData but 协程原生)事件广播、多订阅者消息传递、背压处理
缓存始终缓存当前最新值可配置重放(replay)和额外缓冲(extraBufferCapacity)
背压无(收集者OnBufferOverflow默认SUSPEND,可配置DROP_OLDEST/DROP_LATEST)支持配置背压策略(SUSPEND / DROP_OLDEST / DROP_LATEST)
线程安全全面线程安全(内部同步)全面线程安全
生命周期不绑定Android生命周期,但可通过viewModelScope / lifecycleScope管理不绑定生命周期

1.2 与LiveData对比

LiveData是Android Jetpack中的生命周期感知型数据持有者,在协程出现前是状态管理的首选。StateFlow和SharedFlow的出现提供了更强大的协程集成能力。下表列出关键差异:

维度LiveDataStateFlowSharedFlow
协程原生否(需额外转换)是(完全基于Flow)是
持有最新值是(通过value)是(通过value)可配置(replay>=1时)
生命周期感知内置(自动停止/恢复)无(需手动绑定作用域)无
背压处理无(只能丢弃旧值或阻塞主线程)支持(SUSPEND / DROP)支持,且可独立配置
多订阅者支持(自动去重)支持(每个收集者独立收集器)支持(可共享同一buffer)
事件一次性消费不原生支持(需封装Event包装类)不原生支持(可通过SharedFlow重放0实现)原生支持(replay=0,事件只被新订阅者接收一次)
测试难度较低(依赖Android Arch)较低(纯Kotlin协程测试)较低
最佳实践: 新项目中推荐优先使用StateFlow代替LiveData进行状态管理,使用SharedFlow代替EventBus或BroadcastChannel进行一次性事件广播。迁移时可通过.asLiveData()扩展将StateFlow转为LiveData以兼容旧代码。

1.3 协程基础回顾(Flow & Collect)

StateFlow和SharedFlow本质上是Flow接口的子类型,因此理解Flow的基本操作是必要的。

  • Flow: 冷数据流,每次调用collect时重新执行生产者代码。
  • StateFlow: 热流,将value暴露给多个收集器,收集器只会收到从订阅时刻开始的最新值(如果已有初始值)。
  • SharedFlow: 热流,通过MutableSharedFlow配置重放数、缓冲容量和背压策略,收集器可以收到历史重放值和后续新值。
  • Collect: 挂起函数,在协程作用域内持续执行,直到协程取消或flow完成。
  • 作用域管理: 通常使用viewModelScope(Android)或CoroutineScope管理收集协程的生命周期。

以下为最简单StateFlow使用示例:

class MyViewModel : ViewModel() {
    private val _uiState = MutableStateFlow("Initial")
    val uiState: StateFlow<String> = _uiState.asStateFlow()

    fun updateState(newValue: String) {
        _uiState.value = newValue  // 线程安全更新
    }
}

// 在Activity/Fragment中收集
lifecycleScope.launch {
    viewModel.uiState.collect { value ->
        textView.text = value
    }
}

SharedFlow典型使用(一次性事件):

class EventBus {
    private val _events = MutableSharedFlow<Event>(replay = 0, extraBufferCapacity = 1)
    val events: SharedFlow<Event> = _events.asSharedFlow()

    suspend fun emit(event: Event) {
        _events.emit(event)
    }
}

// 收集事件(只接收发射后的事件)
lifecycleScope.launch {
    eventBus.events.collect { event ->
        // 处理事件
    }
}

1.4 核心概念对比图

StateFlow / SharedFlow / LiveData 对比 数据源(生产者) StateFlow 缓存最新值 SharedFlow 可配置重放/缓存 LiveData 生命周期感知 订阅者A 订阅者B 订阅者C(Observer) 说明 StateFlow: 只发最新值 SharedFlow: 可重放历史 LiveData: 绑定生命周期
常见错误:
  • 将StateFlow用于一次性导航事件:StateFlow始终持有最新值,重复收集会导致导航事件被多次触发。此时应使用SharedFlow(replay=0)。
  • 未指定SharedFlow的replay参数导致事件丢失:默认replay=0,新订阅者收不到历史数据;若需要catch-up则需要设置replay>0。
  • 在不可取消的协程中使用collect导致内存泄漏:始终绑定协程作用域(如lifecycleScope、viewModelScope)。

1.5 本章小结