Android 高级工程师面试:Flow 与状态流 近1年高频追问 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()) } 暴露数据;ViewModel collect 后才开始查库,避免无 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),UI collect SharedFlow 处理单次副作用。

  • 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 会自动停收吗?

    不会,需 repeatOnLifecycleflowWithLifecycle 控制;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 → ViewModel stateIn → 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>,Compose when(state) 分支展示;避免多个 LiveData 碎片状态难以组合。

  • 和 MVI 的 Intent 关系?

    UIState 是 MVI 的 State 部分;Intent 触发 reducer 更新 StateFlow。


#12 repeatOnLifecycle 解决什么问题? 🔥

标准回答

lifecycleScope.launch 里直接 collectonStop 后仍可能收流浪费资源,且 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 → ViewModel stateIn → 地图页 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,全链路可测可省资源。


相关推荐

Android 高级工程师面试:Kotlin 语法基础 近1年高频追问 22 题

Android 高级工程师面试:Java 基础知识 近1年高频追问 22 题

相关推荐
雨季余静1 小时前
RustDesk Android APK 从零编译全步骤
android
辰合软件1 小时前
通达OA目录结构与核心文件解析
android·数据库·oracle
通玄1 小时前
Jetpack Compose 入门系列(八):Compose 中的副作用处理
android
前端双越老师2 小时前
我多年积累的 100+ 简历优化经验,整理成了 Skill
面试·agent
weedsfly2 小时前
防抖与节流:从原理到 React Hook 封装
前端·javascript·面试
黄敬峰2 小时前
🚀 掘金独家:打造最值钱的 AI Agent——从核心概念到高性能代码实战
面试
流氓也是种气质 _Cookie2 小时前
如何创建MCP
android·adb
Kapaseker2 小时前
扶我起来,Compose Styles API 进阶
android·kotlin
_abab3 小时前
Java面试宝典:从基础到架构2
java·面试·架构