文章目录
- 学习建议
- [基础层(8 题)](#基础层(8 题))
-
- [#1 Flow 是什么?为什么说它是冷流? 🔥](#1 Flow 是什么?为什么说它是冷流? 🔥)
- [#2 冷流和热流有什么区别? 🔥](#2 冷流和热流有什么区别? 🔥)
- [#3 StateFlow 是什么?和 MutableStateFlow 怎么用? 🔥](#3 StateFlow 是什么?和 MutableStateFlow 怎么用? 🔥)
- [#4 SharedFlow 是什么?和 StateFlow 差在哪? ⭐](#4 SharedFlow 是什么?和 StateFlow 差在哪? ⭐)
- [#5 StateFlow 和 LiveData 怎么选? 🔥](#5 StateFlow 和 LiveData 怎么选? 🔥)
- [#6 collect 和 collectLatest 有什么区别? 🔥](#6 collect 和 collectLatest 有什么区别? 🔥)
- [#7 flowOn 是干什么的? ⭐](#7 flowOn 是干什么的? ⭐)
- [#8 Room 返回 Flow 是怎么工作的? ⭐](#8 Room 返回 Flow 是怎么工作的? ⭐)
- [进阶层(7 题)](#进阶层(7 题))
-
- [#9 stateIn 和 shareIn 解决什么问题? 🔥](#9 stateIn 和 shareIn 解决什么问题? 🔥)
- [#10 Flow 背压怎么处理?buffer 和 conflate 区别? ⭐](#10 Flow 背压怎么处理?buffer 和 conflate 区别? ⭐)
- [#11 UIState 模式在 Flow 架构里怎么设计? 💡](#11 UIState 模式在 Flow 架构里怎么设计? 💡)
- [#12 repeatOnLifecycle 解决什么问题? 🔥](#12 repeatOnLifecycle 解决什么问题? 🔥)
- [#13 combine 和 merge 怎么选? ⭐](#13 combine 和 merge 怎么选? ⭐)
- [#14 catch 和 onCompletion 分别做什么? ⭐](#14 catch 和 onCompletion 分别做什么? ⭐)
- [#15 Channel 和 Flow 有什么区别? ⭐](#15 Channel 和 Flow 有什么区别? ⭐)
- [核心层(7 题)](#核心层(7 题))
-
- [#16 callbackFlow 使用场景与关闭注意点? 🔥](#16 callbackFlow 使用场景与关闭注意点? 🔥)
- [#17 distinctUntilChanged 解决什么问题? ⭐](#17 distinctUntilChanged 解决什么问题? ⭐)
- [#18 WhileSubscribed 策略是什么意思? 💡](#18 WhileSubscribed 策略是什么意思? 💡)
- [#19 collectAsStateWithLifecycle 怎么用? 🔥](#19 collectAsStateWithLifecycle 怎么用? 🔥)
- [#20 SharedFlow 的 replay 参数怎么理解? ⭐](#20 SharedFlow 的 replay 参数怎么理解? ⭐)
- [#21 MVVM 中 Flow 全链路怎么串? 💡](#21 MVVM 中 Flow 全链路怎么串? 💡)
- [#22 生产消费速率不匹配时如何选型操作符? 💡](#22 生产消费速率不匹配时如何选型操作符? 💡)
- 面试策略速查
- 完整链路一句通
- 相关推荐
学习建议
| 目标层级 | 建议 |
|---|---|
| 初级 | 掌握基础层 8 题:冷流特征、StateFlow vs LiveData、collect/collectLatest、flowOn、Room Flow;工程联想看追问第 1 条 |
| 中级 | 通读全文;进阶层能讲清 stateIn/shareIn、背压、repeatOnLifecycle、combine/merge、Channel vs Flow |
| 高级 | 核心层加分项必答:callbackFlow、whileSubscribed、UIState 模式、MVVM 全链路;能串联「Room→stateIn→collectAsStateWithLifecycle」 |
基础层(8 题)
#1 Flow 是什么?为什么说它是冷流? 🔥
标准回答
Flow 是协程里的异步数据流 API,按「拉取」模型工作;冷流 指只有下游 collect 时上游 flow {} 代码块才执行。每个收集者获得独立执行;无订阅则无生产,与 Sequence 类似但支持挂起与背压。
面试官可能继续追问
-
Android 里冷流典型用法?
Repository 用
flow { emit(dao.query()) }暴露数据;ViewModelcollect后才开始查库,避免无 UI 时白跑网络/数据库。 -
不用 Flow 用 suspend 函数不行吗?
单次结果用 suspend;持续变化(DB 观察、分页)用 Flow 更合适。
#2 冷流和热流有什么区别? 🔥
标准回答
冷流(Flow) :无收集者不运行;多收集者多份独立上游。热流(StateFlow/SharedFlow/Channel):上游独立运行,新订阅者拿当前/历史值,共享同一数据源。
面试官可能继续追问
-
Android 里冷流和热流怎么区分?
flow { }拉取接口是冷流;MutableStateFlow缓存 UI 状态是热流。混淆会导致重复请求或状态不同步。 -
冷流能变热吗?
可以,用
stateIn/shareIn把冷 Flow 转为热 StateFlow/SharedFlow。
#3 StateFlow 是什么?和 MutableStateFlow 怎么用? 🔥
标准回答
StateFlow 是带当前值的热流,要求初始值;value 始终可读,等价于响应式 var。使用 CAS 更新;collect 先收到当前值再收后续变更;多收集者共享同一状态。
面试官可能继续追问
-
Android 里 StateFlow 怎么用?
ViewModel 暴露
StateFlow<UiState>,内部MutableStateFlow更新;Compose 用collectAsStateWithLifecycle驱动重组。 -
能直接暴露 MutableStateFlow 吗?
不推荐,对外应
asStateFlow()只读,写操作封装在 ViewModel 方法里。
#4 SharedFlow 是什么?和 StateFlow 差在哪? ⭐
标准回答
SharedFlow :热流,可无初始值;靠 replay/extraBufferCapacity 配置缓存与缓冲。对比 StateFlow:StateFlow 必有初值、只关心最新态;SharedFlow 适合事件流(导航、Toast、Snackbar)。
面试官可能继续追问
-
Android 里 SharedFlow 典型场景?
viewModelScope里_events.emit(NavigateToDetail),UIcollectSharedFlow 处理单次副作用。 -
replay=0 新订阅能看到历史吗?
不能,只收订阅后的 emit;要重放需
replay > 0。
#5 StateFlow 和 LiveData 怎么选? 🔥
标准回答
StateFlow 优势 :协程原生、类型安全、易与 Flow/Room 组合、stateIn 统一冷转热;Compose 一等公民。LiveData 优势:生命周期自动感知、Java 项目遗留、部分旧 Jetpack API 仍绑定。
面试官可能继续追问
-
Android 里 StateFlow 和 LiveData 怎么选?
新 Kotlin 工程默认 StateFlow +
repeatOnLifecycle/collectAsStateWithLifecycle;维护 LiveData 项目可渐进迁移。 -
StateFlow 会自动停收吗?
不会,需
repeatOnLifecycle或flowWithLifecycle控制;LiveData 内置LifecycleOwner感知。
#6 collect 和 collectLatest 有什么区别? 🔥
标准回答
collect :顺序处理每个值,上游 emit 会等当前处理完。collectLatest :新值到来取消上一次处理协程,只保证最新一次跑完。
面试官可能继续追问
-
Android 里 collect 和 collectLatest 怎么选?
搜索框防抖用
collectLatest------用户快速输入时取消旧请求只保留最新;写库/记账等不可中断操作用collect。 -
和 debounce 操作符关系?
debounce减少 emit 频率;collectLatest减少并发处理,常组合使用。
#7 flowOn 是干什么的? ⭐
标准回答
flowOn 切换其上游 (含自身之前操作符)的运行线程/调度器,不影响下游 collect 所在上下文。本质是上下文切换边界;多次 flowOn 只影响各自上游段。
面试官可能继续追问
-
Android 里 flowOn 怎么用?
repository.getUsers().flowOn(Dispatchers.IO).collect { ... }在 IO 查库,回主线程更新 UI(collect 若在 Main)。 -
和 withContext 区别?
withContext在 flow 块内切换;flowOn是声明式操作符,适合链式组合。
#8 Room 返回 Flow 是怎么工作的? ⭐
标准回答
DAO @Query 返回 Flow<List<Entity>>,表变化时 Room 自动 re-query 并 emit 新列表。内部观察 InvalidationTracker;冷 Flow 形态,但数据源由 Room 驱动刷新。
面试官可能继续追问
-
Android 里 Room Flow 怎么串?
dao.observeTodos()→ Repository 转发或map→ ViewModelstateIn→ UI collect;删改表后列表自动更新,无需手动 refresh。 -
和 Paging
PagingSource怎么配合?列表分页用 Paging3;单表全量观察用小表 Flow,大列表勿直接
Flow<List>拉全量。
进阶层(7 题)
#9 stateIn 和 shareIn 解决什么问题? 🔥
标准回答
冷 Flow 多收集者会重复执行(重复网络/计算);需在合适层共享一份热流。stateIn :转 StateFlow,需 initialValue + SharingStarted 策略。shareIn :转 SharedFlow,可配 replay;适合共享事件或非状态流。
面试官可能继续追问
-
Android 里 stateIn 怎么用?
repo.userFlow.stateIn(viewModelScope, WhileSubscribed(5_000), UserUiState.Loading)多界面共享且无人订阅时停上游。 -
stateIn 在 Repository 还是 ViewModel?
常在 ViewModel 转 UI 态;Repository 保持冷 Flow 更易测与复用。
#10 Flow 背压怎么处理?buffer 和 conflate 区别? ⭐
标准回答
背压 :生产快于消费时,默认挂起生产者(挂起式 Flow)。buffer :加缓冲队列,解耦上下游速度。conflate:只保留最新值,丢弃中间积压,适合 UI 只关心最新态。
面试官可能继续追问
-
Android 里背压操作符怎么选?
传感器高频采样 →
conflate()再更新 UI;下载进度可buffer避免阻塞 IO。 -
buffer 会无限增长吗?
受容量限制,满则按策略挂起或丢弃。
#11 UIState 模式在 Flow 架构里怎么设计? 💡
标准回答
用密封类/数据类封装 Loading | Success(data) | Error(msg),单一 StateFlow<UiState> 驱动 UI。状态可预测、可测试;副作用(导航/Toast)与状态分离,走 SharedFlow 或事件通道。
面试官可能继续追问
-
Android 里 UIState 模式怎么落地?
HomeViewModel暴露StateFlow<HomeUiState>,Composewhen(state)分支展示;避免多个 LiveData 碎片状态难以组合。 -
和 MVI 的 Intent 关系?
UIState 是 MVI 的 State 部分;Intent 触发 reducer 更新 StateFlow。
#12 repeatOnLifecycle 解决什么问题? 🔥
标准回答
在 lifecycleScope.launch 里直接 collect,onStop 后仍可能收流浪费资源,且 onStart 需手动重订。repeatOnLifecycle 在指定状态(通常 STARTED)内启动协程,STOPPED 自动取消,再次 STARTED 重新收集。
面试官可能继续追问
-
Android 里 repeatOnLifecycle 怎么用?
viewLifecycleOwner.repeatOnLifecycle(STARTED) { vm.uiState.collect { render(it) } }替代旧式launchWhenStarted。 -
和 launchWhenStarted 区别?
launchWhenStarted仅暂停不取消协程,易泄漏;repeatOnLifecycle会取消并在恢复时重启。
#13 combine 和 merge 怎么选? ⭐
标准回答
combine :等多路 Flow 都有值后,任一路更新就重新计算组合结果。merge:多路合并为一路,谁先 emit 谁先出,不等待对齐。
面试官可能继续追问
-
Android 里 combine 和 merge 怎么选?
combine(userFlow, settingsFlow) { u, s -> ... }拼 UI;合并多个点击事件源用merge。 -
和 zip 区别?
zip按配对一对一;combine用各路最新值重算。
#14 catch 和 onCompletion 分别做什么? ⭐
标准回答
catch :捕获上游异常,可 emit 兜底值或再抛;只能捕上游,不能捕下游 collect 块异常。onCompletion :无论正常完成还是异常取消都会回调,适合做清理、埋点;cause 参数区分取消与失败。
面试官可能继续追问
-
Android 里 catch/onCompletion 怎么用?
网络 Flow
.catch { emit(emptyList()) }防崩溃;.onCompletion { hideLoading() }统一收尾。 -
CancellationException 要被 catch 吗?
不应吞掉,应 rethrow,否则协程取消语义被破坏。
#15 Channel 和 Flow 有什么区别? ⭐
标准回答
Channel :热、多生产者多消费者队列,默认无背压协调(需选容量策略)。Flow:冷、通常单收集者语义清晰,内置挂起式背压,操作符丰富。
面试官可能继续追问
-
Android 里 Channel 和 Flow 怎么选?
UI 一次性事件可用
Channel/SharedFlow;数据管道、Room、网络链优先 Flow。 -
Flow 能多个收集者吗?
冷流可以但各自跑上游;共享用 shareIn。
核心层(7 题)
#16 callbackFlow 使用场景与关闭注意点? 🔥
标准回答
把回调式 API(Location、Sensor、addOnCompleteListener)桥接为 Flow。写法:callbackFlow { val cb = ...; register(cb); awaitClose { unregister(cb) } }。awaitClose 必须注销监听,否则泄漏;trySend 用于非挂起回调线程。
面试官可能继续追问
-
Android 里 callbackFlow 典型场景?
FusedLocationProvider 持续定位 →
callbackFlow→ ViewModelstateIn→ 地图页 collect。 -
callbackFlow 是冷还是热?
冷 Flow 包装;收集时才注册回调。
#17 distinctUntilChanged 解决什么问题? ⭐
标准回答
连续相等值不向下游 emit,减少无效 UI 刷新。默认用 ==;可自定义 areEquivalent 只比较关键字段。
面试官可能继续追问
-
Android 里 distinctUntilChanged 怎么用?
stateIn前的userFlow.distinctUntilChanged()避免同用户对象重复触发 Compose 重组。 -
和 debounce 组合顺序?
常先 debounce 再 distinct,视场景;搜索可先 debounce 减少比较次数。
#18 WhileSubscribed 策略是什么意思? 💡
标准回答
SharingStarted.WhileSubscribed(stopTimeoutMillis) 表示无订阅者 超过超时后停止上游,有新订阅再重启。省电量与网络;比 Eagerly 更安全,比裸 Lazily 更及时。
面试官可能继续追问
-
Android 里 WhileSubscribed 怎么用?
详情页
stateIn(..., WhileSubscribed(5_000), ...),用户离开 5 秒后停同步,返回页面自动重新拉取。 -
超时设 0 会怎样?
无订阅立即停上游,适合严格节省资源。
#19 collectAsStateWithLifecycle 怎么用? 🔥
标准回答
Compose 中收集 StateFlow/Flow,生命周期低于 STARTED 时暂停更新,避免后台重组浪费。用法:val state by vm.uiState.collectAsStateWithLifecycle(),需 lifecycle-runtime-compose 依赖。
面试官可能继续追问
-
Android 里 collectAsStateWithLifecycle 怎么用?
Material3 页面统一用 WithLifecycle 版本;与
repeatOnLifecycle在 View 体系形成对称方案。 -
Flow 冷流直接 collectAsState 会怎样?
会在 Composition 里启动收集,更推荐 ViewModel 里 stateIn。
#20 SharedFlow 的 replay 参数怎么理解? ⭐
标准回答
replay :新订阅者立即收到最近 N 个已 emit 值,再收后续。旋转屏后 ViewModel 存活,UI 重建需补发最近导航事件要谨慎------事件流常 replay=0;缓存最近配置可用 replay=1。
面试官可能继续追问
-
Android 里 SharedFlow replay 怎么配?
MutableSharedFlow(replay=0, extraBufferCapacity=1)处理点击防抖事件;replay=1适合「最近一次刷新信号」类需求。 -
replay 和 StateFlow 初始值区别?
StateFlow 始终有当前 value;SharedFlow replay 是历史 emit 缓冲,可无初值。
#21 MVVM 中 Flow 全链路怎么串? 💡
标准回答
链路 :Room/Network 冷 Flow → Repository map/错误处理 → ViewModel stateIn(WhileSubscribed) 得 StateFlow<UiState> → UI collectAsStateWithLifecycle / repeatOnLifecycle。一次性副作用走 SharedFlow/Channel,与 UiState 分离。
面试官可能继续追问
-
Android 里 MVVM + Flow 全链路例子?
典型 Feed 页:DAO
observePosts()→ Repo → VM 转PostsUiState→ LazyColumn 展示;配置变更 ViewModel 保留 stateIn 热流。 -
旋转屏数据为何还在?
ViewModel scope 未销毁,StateFlow 持续;UI 重新 collect 拿当前值。

#22 生产消费速率不匹配时如何选型操作符? 💡
标准回答
只关心最新 :conflate() 或 collectLatest。不能丢任何值 :buffer() 扩大缓冲,或放慢生产端。要采样/防抖 :debounce/sample 减 emit 频率。转热共享 :stateIn/shareIn 避免多 collector 重复拉取。
面试官可能继续追问
-
Android 里速率不匹配怎么选型?
股票行情高频 tick →
sample(500)+distinctUntilChanged;表单校验 →debounce(300)+collectLatest调接口。 -
flatMapMerge 和背压关系?
flatMapMerge并发子 Flow,默认有并发上限,仍要注意下游处理能力。
面试策略速查
| 面试等级 | 建议掌握 |
|---|---|
| 初级 | ★★★☆☆ |
| 中级 | ★★★★☆ |
| 高级 | ★★★★★ |
必背知识(🔥)
冷流特征、冷/热对比、StateFlow、StateFlow vs LiveData、collect/collectLatest、stateIn/shareIn、repeatOnLifecycle、callbackFlow、collectAsStateWithLifecycle
高频追问
「冷流为何多执行」「StateFlow 和 SharedFlow 选型」「LiveData 还要学吗」「stateIn 放哪一层」「repeatOnLifecycle 和 launchWhenStarted」
加分项(💡)
UIState 模式、WhileSubscribed、MVVM 全链路、背压操作符选型、SharedFlow replay 配置
容易踩坑
冷 Flow 多 collector 重复请求;用 StateFlow 发一次性导航事件;不用 repeatOnLifecycle 后台仍 collect;callbackFlow 忘记 awaitClose 注销;吞掉 CancellationException;Room 大表全量 Flow
完整链路一句通
Flow 状态流一条线:数据源(Room/网络/callbackFlow)以冷 Flow 暴露,Repository 清洗转换,ViewModel 用 stateIn/WhileSubscribed 转热 StateFlow 承载 UiState,一次性事件走 SharedFlow;UI 在 STARTED 内 collectAsStateWithLifecycle 或 repeatOnLifecycle 安全订阅,背压与去重靠 buffer/conflate/distinctUntilChanged,全链路可测可省资源。