Flow 是一条数据管道
Flow 把一串随时间到来的数据变成一条管道:源头吐数据,中间一层层操作符过滤变换,末端收集结果。它和协程一样挂在作用域里,生命周期跟着走,不用时自动取消,不会泄漏。
把数据想成水流:源头是泉水,操作符是一道道阀门,收集端是出口。
这篇聊操作符怎么用、冷热流怎么选、背压怎么治。
常用操作符
操作符是管道上的阀门。map 把每个值变个样,filter 留下符合条件的,distinctUntilChanged 去掉连续重复,debounce 在一段时间静默后才吐值。把它们串起来,源头到收集端之间就是一条成型的数据加工线。
操作符速查
- map逐项变换。
- filter留下满足条件的值。
- debounce静默后才发射,适合搜索框。
冷流与热流
普通 Flow 是冷的:没人收集它就不产数据,每个收集者都有自己独立的一份流。StateFlow、SharedFlow 是热的:它们有当前值,多个收集者共享同一份,像一个一直在播报的电台。要共享状态用热流,要单次处理用冷流。
// 冷流:collect 才开始跑
flowOf(1, 2, 3)
.map { it * 2 }
.collect { println(it) }
选错冷热,数据就对不上界面预期。
背压是什么
当源头吐数据比末端处理快,数据就在管道里越积越多,这就是背压。比如传感器一秒推一百个值,界面一帧只能画一次,积压的中间值就成了累赘。Flow 默认会等末端,但有时你只想拿最新的。
背压的几种应对
处理背压有三板斧:用 conflate 合并中间值,只留最新的;用 sample 按固定间隔取样;用 buffer 给处理留个缓冲间。按场景挑——滑动列表要最新就 conflate,统计采样就 sample。
- conflate:丢中间、保最新。
- sample:按节奏取样。
- buffer:给处理留缓冲。
在界面层收集
界面层用 repeatOnLifecycle 在可见时收集、不可见时暂停,避免后台空跑。把 StateFlow 直接绑到界面状态,数据一变界面就刷新,整条链路从数据源头到屏幕画面对齐了。
实战:节流搜索框
做一个搜索框:用户边打边搜,但只在停顿后才发请求。
queryFlow
.debounce(300)
.distinctUntilChanged()
.flatMapLatest { repo.search(it) }
.collect { showResult(it) }
debounce 等停顿、去重、再用 flatMapLatest 只取最后一次。搜索做到这份上,既跟手又不把后端打爆。