Kotlin中的flow、stateflow、shareflow之间的区别和各自的功能 - 教程
2025-11-14 20:36 tlnshuju 阅读(0) 评论(0) 收藏 举报(
Flow、StateFlow、SharedFlow) 是 Kotlin 协程 Flow 家族中最核心的三种类型,常用于 MVVM 架构中实现 异步数据流、状态管理、事件分发。
| 特性 | Flow | StateFlow | SharedFlow |
|---|---|---|---|
| 热/冷流 | ❄️ 冷流(每次收集重新执行) | 热流(始终活跃) | 热流(始终活跃) |
| ♂️ 单播 / 多播 | 单播(每个收集者独立执行) | 多播(共享最新状态) | 多播(共享事件流) |
| 是否缓存最新值 | 否 | ✅ 是(value 属性) | ✅ 可选(replay 参数决定) |
| ⏱️ 是否立即发送最后值给新订阅者 | 否 | ✅ 是(新订阅立即收到最新值) | ✅ 可配置(取决于 replay) |
| 典型用途 | 一次性数据流(网络请求、文件流) | 持有并共享 UI 状态(ViewModel 状态管理) | 分发一次性事件(Toast、导航) |
| ⚙️ 背压(Backpressure) | ✅ 自动支持(挂起下游以等待) | 不支持真正的背压(最新值覆盖旧值) | ⚠️ 可配置缓存(extraBufferCapacity 控制溢出行为) |
| 空值限制 | 允许为 null | ❌ 不允许 null(需初始化) | 允许为 null |
| 类似概念(RxJava 对应) | Observable / Flowable | BehaviorSubject | PublishSubject / ReplaySubject |
1. Flow - 基础数据流(冷流)
核心特性
冷流(Cold Stream):每次收集时重新开始执行
单订阅:每个收集者都会获得独立的数据流
可取消:跟随协程作用域的生命周期
操作符丰富:支持
map,filter,transform等场景:网络请求、数据库查询、搜索接口、分页加载
使用实例:
fun getUserListFlow(): Flow> = flow {val users = api.getUserList() // 每次 collect 都会调用emit(users)
}
lifecycleScope.launch {viewModel.getUserListFlow().collect { list ->showUserList(list)}
}
2. StateFlow - 状态容器
核心特性
热流(Hot Stream):不管有没有收集者都会存在
必须有初始值:不能为空
状态保持:保留最新值,新订阅者立即获得当前值
值去重:只有值发生变化时才通知收集者
UI状态管理:专为管理UI状态设计
类似LiveData,但支持协程 + 背压
使用实例:
private val _uiState = MutableStateFlow("初始状态")
val uiState: StateFlow = _uiState
fun updateState(newState: String) {_uiState.value = newState
}
lifecycleScope.launchWhenStarted {viewModel.uiState.collect { state ->textView.text = state}
}
3. SharedFlow - 事件总线
特点
也是热流,但不强制持有当前值
可配置 replay 缓存数量
常用于一次性事件:Toast、导航、弹窗、通知等
热流(Hot Stream):独立于收集者存在
无初始值:不需要初始值
广播事件:向所有收集者发送事件
配置灵活:可配置重放数量、缓存大小等
特性
| 特性 | 说明 |
|---|---|
replay = 0 | 不缓存,收集后才会接收到事件(默认) |
replay = 1 | 缓存最近一个事件(新订阅者会收到) |
extraBufferCapacity | 控制缓冲区大小,防止背压丢失 |
onBufferOverflow | 配置溢出策略(DROP_OLDEST / DROP_LATEST / SUSPEND) |
使用实例:
private val _eventFlow = MutableSharedFlow()
val eventFlow = _eventFlow.asSharedFlow()
fun sendToast(msg: String) {viewModelScope.launch {_eventFlow.emit(msg)}
}
lifecycleScope.launchWhenStarted {viewModel.eventFlow.collect { msg ->Toast.makeText(context, msg, Toast.LENGTH_SHORT).show()}
}
实际项目中的组合使用
class ProductViewModel : ViewModel() {// StateFlow - 管理UI状态private val _uiState = MutableStateFlow(ProductUiState.Loading)val uiState: StateFlow = _uiState.asStateFlow()// SharedFlow - 管理一次性事件private val _events = MutableSharedFlow()val events: SharedFlow = _events.asSharedFlow()// Flow - 数据转换流val recommendations: Flow> = flow {val products = productRepository.getProducts()val filtered = products.filter { it.isRecommended }emit(filtered)}fun loadProduct(productId: String) {viewModelScope.launch {// 使用 Flow 进行网络请求productRepository.getProductFlow(productId).catch { e ->// 通过 SharedFlow 发送错误事件_events.emit(ProductEvent.ShowError(e.message ?: "Unknown error"))}.collect { product ->// 更新 StateFlow 状态_uiState.value = ProductUiState.Success(product)}}}
}
选择指南
使用 Flow:需要复杂数据转换、单次数据获取、数据库观察
使用 StateFlow:管理UI状态、需要保持最新状态、状态驱动UI
使用 SharedFlow:处理一次性事件、广播消息、用户交互事件
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/965701.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!相关文章
非离散网络流——P3347 [ZJOI2015] 醉熏熏的幻想乡
非离散网络流——P3347 [ZJOI2015] 醉熏熏的幻想乡
观察费用为 \(a_ix^2+b_ix\),如果是离散的,则可以套路的建边 \(a_i+b_i,3a_i+b_i,5a_i+b_i,\dots\),可本题 \(x\in R\)。
于是连续意义下我们应该求导得到 \(2a_i…
[note] 素数判定与分解质因数
在某些毒瘤的数论题中,可能出现对 \(10^{18}\) 的范围内的数质因数分解的情况。这时,可以使用 Fermat 和 Miller-Rabin 算法进行素性判定,Pollard-Rho 算法寻找非平凡因子,两者结合以快速质因数分解。
Fermat 素性…
不能识别adb/usb口记录 - 实践
pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …
恭喜自己,挑战成功! - Ghost
恭喜自己,挑战成功!
我终于,拿省一啦!
正文:
在2025年8月18日,本人开始了一项挑战
挑战三个月达省一
在三个月后,2025年11月14日,NOI官网发布了分数and分数线
本人以高出一等分数线10分的分数(250pts),成功…
如何在测试覆盖不足后补充验证
测试覆盖不足是项目质量的重大隐患,一旦发现(尤其是当它已导致线上问题时),团队必须立即采取系统性的补充验证措施。核心策略是停止盲目开发,转而执行一套以风险为导向的补救流程。 首先,必须立即对未覆盖的区域…
完整教程:PDFBox - PDDocument 与 byte 数组、PDF 加密
pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …
Dark Side of the Moon
“Speak to Me”
"Ive been mad for fucking years, absolutely years, been over the edge for years, been working me buns off for bands..."
"Ive always been mad, I know Ive been mad, like mo…
flask:自定义异常
一,代码:
自定义异常:class ApiError(Exception):""""API接口异常错误"""messsage = ""# 默认错误码status_code = 400# 自定义一个return_code, 作为更细粒的错误代码…
OpenWrt路由的端口映射问题
之前做过AI大模型搭建,想将搭建的访问能开放到外部局域网,方便其他人访问,需要一些网络设置,就在这个网络配置上踩了些坑。
想在最外局域网中访问,但是自己这边用了两级的路由,第一级是小米的无线路由,以及上一…
解码IPC-管道与信号
进程间通信(IPC)
进程间通信(Inter Process Communication,简称 IPC)是进程间的信息交换,核心目的包括数据传输、共享资源、控制进程,方便对进程的管理与调度。常见 IPC 方式有管道通信、信号通信、共享内存、消…
算法沉淀第七天(AtCoder Beginner Contest 428 和 小训练赛) - 详解
pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …
How-to-extract-text-from-PDF-Image-files-OCR-CarlZeng
本文阐述如何自建并使用OCR识别图片或PDF中文字(转化成文本等进一步处理), 以及NetSuite调用OCR API的场景雏形.
How to extract text from PDF(Image) files. 20251113 引入自建ocr服务docker部署OCR项目
支持离线+…
Web应用模糊测试完全指南
本文详细介绍了使用ffuf工具进行Web应用模糊测试的完整流程,包括目录发现、子域名枚举、暴力破解攻击、参数挖掘等多种技术,提供了实用的命令示例和配置参数说明。Fuzzing Web Apps Full Guide
前言
在这篇博客中,我…
升鲜宝供应链管理系统、各端的访问地址及nginx 真实的配置方法
server {listen 443 ssl;server_name sxbscm.sxbscm.com;# 1. SSL 证书配置(关键:补充中间证书,避免链不完整导致兼容问题)ssl_certificate /mnt/sxbscm/ssl/sxbscm.sxbscm.com/sxbscm.sxbscm.com.pem; # 主证书(…
2025.11.14模拟赛
IOI赛制,fjj的模拟赛,题目质量非常高(准确来说是非常适合我们),fjj强大的%%%
赛时看T1,然后打了60暴力,已经知道用组合数来求了,然后也知道固定左上角的来求答案,但是就是没想明白怎么去除重复的贡献
然后一看…
【HT-086-Div.2】错乱的集合
【HT-086-Div.2】错乱的集合 题解比赛现场
更阅读体验的阅读体验
是个好题。但是我赛时怎么什么都不会。首先简化一下题面:\(s\) 和 \(t\) 被认为是相同的,当且仅当 \(s=t\) 或 \(|t|=|s|-1\) 且 \(t\) 是 \(s\) 的后…
uiautomator2元素查看器WEditor的安装和启动
WEditor
一、WEditor简介
在执行APP UI自动化测试时,需要使用到元素定位,通常我们会直接使用appium Desktop的Inspector。介绍另一款UI元素定位的工具--WEditor。WEditor能够提供辅助编写脚本,定位元素,调试代码等…