把十八章压进一场面试
好的回答不是把知道的全倒出来,而是先给判断,再给机制、取舍和一段亲手做过的证据。
面试官问:「StateFlow 和 SharedFlow 有什么区别?」最好的开头是哪句?
- 把两者所有构造参数背一遍
- 「一个有 value,一个没有」
- 「先看你要表达当前状态,还是一次广播事件」
- 「项目里统一用 StateFlow」
六个三十秒答案
- 生命周期:「我先区分配置变更、页面离开与进程死亡。ViewModel 只跨配置变更;短小 UI 输入进保存状态;不能丢的业务事实先落数据库,跨进程工作交 WorkManager。」
- 协程:「suspend 允许暂停,不保证后台执行。scope 定寿命,Dispatcher 定执行政策;普通 scope 共命运,supervisor 隔离兄弟失败;底层 API 应主线程安全。」
- Flow:「冷流每个 collector 重启生产;StateFlow 表示有当前值的共享状态;SharedFlow 是可配置重放的广播。选择先看订阅、重放、丢失和慢消费者语义。」
- Compose:「Composable 是可重放描述。状态读取决定重组范围,位置或 key 决定身份,稳定参数允许跳过。副作用必须放 Effect,并明确 key 与清理。」
- 架构:「UI 观察不可变状态、事件上行;数据层拥有业务事实。Repository 定义来源与一致性政策,领域层只在规则复杂或复用时添加。」
- 离线消息:「先事务写本地消息与 outbox,UI 只观察 Room;Worker 带同一幂等键重试;服务端给会话序号;推送只触发游标补洞。」
系统设计题:安全医疗消息
先问约束,不要立刻画框:一对一还是群组?顺序要求到会话还是全局?允许离线多久?附件大小?消息能否撤回?设备丢失后如何撤销?通知可显示多少?合规地区与保留期?多端是否同时在线?
接着说五个不变量:
- 用户按发送后,意图要么明确失败,要么可恢复地进入本地队列。
- 未知结果可安全重试,服务端效果至多一次。
- 会话内顺序由服务端定义,客户端待发状态可解释。
- 未授权设备拿不到正文,通知与日志不泄露患者信息。
- 本地敏感副本有最小范围、明确寿命和可审计清理。
然后画链:Compose → ViewModel → Repository → Room+outbox → WorkManager → API → 服务端序号 → Room → UI。最后逐个打故障:断网、超时但已提交、进程死亡、重复推送、令牌过期、数据库满、权限撤销、设备时间错误。每个故障都对应状态、恢复和指标。
针对 Celo Health,值得问的问题
这些问题来自公开产品约束,不假设内部实现:
- 「移动端在安全与离线可用之间,最难的一次取舍是什么?」
- 「Android、iOS 与 Web 的消息顺序和同步合同由哪一层定义?」
- 「临床照片不进入个人相册时,团队如何设计临时存储、上传恢复与清理?」
- 「团队怎样测弱网、大量消息到达、进程死亡与设备型号差异?」
- 「AI Scribe 的音频与草稿在移动端有哪些数据寿命和用户确认边界?」
- 「入职前三个月,这个角色最需要改善的用户旅程或工程指标是什么?」
好问题不是展示你查过官网,而是把产品承诺翻译成工程合同,并邀请对方讲真实取舍。
行为题也要有技术判断
用 STAR 只是保证顺序:Situation 简短交代约束,Task 说清你的责任,Action 重点讲你如何发现信息、权衡方案、拉齐人,Result 给结果与反事实。最后加一句「现在重做我会怎么改」,能显示学习能力。
两年空窗无需防御性解释。可直接说:「我有成熟 Android 基础,过去两年没做原生开发,所以这次按生命周期、协程、Compose、离线架构与质量证据系统恢复;我也用一条安全消息把它们重新接成了完整设计。」诚实承认不记得某个 API,再说查证路径,比硬猜版本号可靠。
定时做一次完整口述。不是默读答案,而是录音后按合同、机制、取舍、证据四项打分:
00:00–00:30 自我介绍:经验、空窗、为什么回来 00:30–02:00 Compose 状态与副作用 02:00–03:30 协程、取消与 Flow 03:30–08:00 离线安全消息系统设计 08:00–10:00 故障矩阵、安全、测试与指标 10:00–12:00 反问 Celo Health
# 手机录音即可;回听时只记四列 判断是否先给出 | 机制是否准确 | 取舍是否具体 | 是否有证据 # 每道题第二遍必须比第一遍短 # 卡住时用这句重启:我先把约束和不变量说清楚。
今天录第一遍,明天只重录最弱的两段,面试前一天录完整第二遍。不要背逐字稿;只记每题的第一句判断与最后一句取舍。
三天冲刺表
| 时间 | 读 | 做 |
|---|---|---|
| 第 1 天 | 01–08:系统、Kotlin、协程、Flow | 写 reducer、进程死亡草稿、幂等重试单测 |
| 第 2 天 | 09–16:Compose、架构、离线、安全 | 搭一页 ChatScreen,口述消息系统设计 |
| 第 3 天 | 17–18+错题回看 | 跑测试、录十二分钟模拟、准备三个项目故事 |
| 面试当天 | 只看六个三十秒答案 | 不再升级工具链,不再开新教程 |
继续往下走
- Compose 运行机制:接着读书架上的《重跑》,补 Snapshot、阶段读取与性能诊断。
- Android 架构变化:读《承重》,对照 Navigation 3、状态持有者与真实项目流派。
- Kotlin 深水区:读《坩埚》,补 inline、协程状态机、型变与 K2 工具链。
- 并发底层:读《同时》,把协程接回线程、内核 I/O、内存模型与背压。
- 官方样板:看 Now in Android,但每抄一个模式都先问它在解决什么规模的问题。
争议点也值得继续:一次性 UI 事件该用状态还是事件流、UseCase 是否默认存在、导航状态该由谁持有、证书固定是否值得。这些没有脱离上下文的唯一答案;成熟度体现在你能列出失败模式。
面试官不一定按这本书的章节问。他可能从一个 bug 切入:「为什么旋转后 Snackbar 又弹了?」你可以沿链回答:事件被当成可重放状态 → 新 collector 收到旧值 → 选择状态内联显示或定义明确的一次性效果 → 用生命周期与重建测试验证。地图比题库耐用。
「准备得越多,回答越长越显得资深。」长答案常把判断埋掉,也不给面试官追问空间。
第一轮控制在三十秒:判断、两句机制、一个取舍。对方追问时再下钻到代码、故障和证据。
答案是第 3 项。StateFlow 与 SharedFlow 的区别不是属性清单,而是语义:前者适合「现在是什么」,后者适合「向当前订阅者广播什么」。从需求合同开头,后续参数才有落脚点。
这一章的一句话
你不需要证明自己记得所有 API;你要证明面对变化、失败和取舍时,仍能把系统推理清楚。
书到这里结束。最后一次练习不是再看一章,而是合上目录,用十二分钟把那条消息从手指送到服务端,再完整送回来。