StateFlow 和 SharedFlow
:替代 LiveData,提供更灵活的协程支持,确保所有订阅者获取最新状态。:确保 UI 始终显示最新状态,避免因配置变更导致的数据丢失。:处理一次性事件(如通知、用户操作),支持灵活的缓冲策略。:额外缓冲容量,用于处理生产者和消费者速度差异。:状态管理工具,用于持久化并同步最新状态值。:通用事件总线,支持广播事件与历史数据回放。:新订阅者回放的历史数据数量(默认 0)。✅ 需要持久
StateFlow 与 SharedFlow 的深度对比与实战指南
一、核心概念与设计目标
-
StateFlow
-
定位:状态管理工具,用于持久化并同步最新状态值。
-
设计目标:替代 LiveData,提供更灵活的协程支持,确保所有订阅者获取最新状态。
-
关键特性:
-
必须设置初始值,始终持有最新状态。
-
新订阅者立即收到当前值(粘性)。
-
自动防抖(相同值不重复触发)。
-
-
-
SharedFlow
-
定位:通用事件总线,支持广播事件与历史数据回放。
-
设计目标:处理一次性事件(如通知、用户操作),支持灵活的缓冲策略。
-
关键特性:
-
无初始值,可配置
replay缓存历史数据。 -
订阅者可能错过未收集的事件(除非设置
replay)。 -
支持背压控制(
buffer、onBufferOverflow)。
-
-
二、核心特性对比
|
特性 |
StateFlow |
SharedFlow |
参考来源 |
|---|---|---|---|
|
初始值 |
✅ 必须设置 |
❌ 无初始值 |
|
|
历史数据 |
仅保留最新值 |
可配置 |
|
|
粘性事件 |
✅ 新订阅者立即接收当前值 |
❌ 除非设置 |
|
|
防抖机制 |
✅ 相同值不重复触发 |
❌ 每次 |
|
|
背压处理 |
无内置策略(依赖 |
支持 |
|
|
适用场景 |
UI 状态管理(如 ViewModel 状态) |
事件广播(如 Toast、导航、日志) |
三、源码实现与参数解析
1. StateFlow 源码特性
-
继承关系:
StateFlow继承自SharedFlow,是SharedFlow的特化版本。 -
核心参数:
-
value:当前状态值,通过MutableStateFlow直接修改。 -
防抖逻辑:内部通过
compareAndSet实现值比较,避免重复触发。
-
2. SharedFlow 关键参数
-
replay:新订阅者回放的历史数据数量(默认 0)。 -
extraBufferCapacity:额外缓冲容量,用于处理生产者和消费者速度差异。 -
onBufferOverflow:缓冲区满时的处理策略:-
BufferOverflow.SUSPEND(默认):挂起生产者直到有空间。 -
BufferOverflow.DROP_OLDEST:丢弃最旧数据。 -
BufferOverflow.DROP_LATEST:丢弃最新数据。
-
示例配置:
val chatFlow = MutableSharedFlow<String>(
replay = 2, // 新订阅者获取最近 2 条消息
extraBufferCapacity = 5, // 额外缓冲 5 条
onBufferOverflow = BufferOverflow.DROP_OLDEST // 溢出时丢弃旧数据
)
四、适用场景与实战案例
1. StateFlow 典型场景
-
UI 状态管理:
class LoginViewModel : ViewModel() { private val _uiState = MutableStateFlow(LoginState.Idle) val uiState: StateFlow<LoginState> = _uiState fun login() { viewModelScope.launch { _uiState.value = LoginState.Loading // 模拟网络请求 delay(1000) _uiState.value = LoginState.Success } } }优势:确保 UI 始终显示最新状态,避免因配置变更导致的数据丢失。
2. SharedFlow 典型场景
-
事件总线:
object EventBus { val navigationEvent = MutableSharedFlow<String>() val toastEvent = MutableSharedFlow<String>() } // 发送事件 viewModelScope.launch { EventBus.navigationEvent.emit("Home") } // 接收事件 lifecycleScope.launch { EventBus.navigationEvent.collect { destination -> findNavController().navigate(destination) } } -
日志系统:
val logFlow = MutableSharedFlow<String>( replay = 0, // 不缓存历史日志 extraBufferCapacity = 100, // 缓冲 100 条日志 onBufferOverflow = BufferOverflow.DROP_OLDEST // 溢出时丢弃旧日志 )
五、性能优化与避坑指南
1. 避免内存泄漏
-
规则:始终在
viewModelScope或lifecycleScope中收集流。lifecycleScope.launchWhenStarted { viewModel.uiState.collect { /* ... */ } }
2. 背压处理策略
-
高频数据:使用
conflate()仅保留最新值。 -
严格顺序:使用
buffer()保证数据顺序处理。 -
资源敏感场景:
onBufferOverflow = DROP_LATEST防止内存爆炸。
3. 线程安全
-
修改状态:在
viewModelScope中更新StateFlow值。 -
发射事件:在
Dispatchers.IO中处理高负载操作。
六、与 LiveData 的对比
|
特性 |
StateFlow/SharedFlow |
LiveData |
|---|---|---|
|
冷热流 |
热流(主动发射) |
冷流(依赖观察者) |
|
生命周期 |
无绑定,需手动管理作用域 |
自动绑定 |
|
线程安全 |
需手动切换线程 |
自动线程安全 |
|
复杂场景 |
支持背压、重放、多消费者 |
仅基础数据同步 |
七、总结与选型建议
-
选 StateFlow 当:
✅ 需要持久化最新状态(如 UI 状态)。
✅ 需要防抖机制避免重复触发。
-
选 SharedFlow 当:
✅ 需要广播事件或历史数据回放。
✅ 需精细控制背压和缓冲策略。
-
避坑提示:
-
避免在
SharedFlow中发送高频数据,可能导致内存溢出。 -
优先使用
StateFlow替代LiveData,获得协程生态优势。
-
通过合理选择流类型,可显著提升应用性能与代码可维护性。
更多推荐


所有评论(0)