重跑
你已经会写 Compose 了。界面出得来,数据也能刷新。然后有一天你发现:输入框里每敲一个字,整个列表都在重组;退出页面之后,那个上传任务还在后台跑了十几秒;切到后台四秒钟,行情收集器白算了四十次;旋转一下屏幕,Snackbar 又弹了一遍。
这些看上去是四个毫不相干的 bug。它们其实是同一个问题的四个侧面——你不知道你写的东西什么时候会被重跑,也不知道重跑的时候,谁该活下来、谁该被扔掉。
这本书的主线只有一句:你写的不是界面,是一个会被反复调用的函数。你要操心的从来不是「怎么跑一遍」,而是重跑的时候——什么活下来、什么重算、什么被取消。
下面是同一个待办屏幕(13 个 composable 节点)上的三个改动,书里那台重组器当场算出来的:
这不是示意图。三行里的每一个数字,都是第 1 章那台重组器算出来的——它就在网页里跑,你可以自己点。
这本书为什么值得你花时间
讲 Compose 的材料已经很多了,但它们大多停在「怎么写」:用 remember 记住状态,用 LaunchedEffect 发请求,用 collectAsStateWithLifecycle 收流。这些你都会。
问题出在下一层:为什么这里要 remember,那里不用?为什么这个 key 写错了会重发请求?为什么 collectAsState 在后台还在跑?这些问题的答案不在 API 文档里,在运行时的行为里——而运行时的行为,只有看见了才记得住。
所以这本书里有六台真东西:
- 一台带 slot 表的重组器。真的位置记忆、真的读取观察、真的失效传播、真的跳过。重组从失效的那个节点开始,不从根开始——书里所有「重跑几个」的数字都是它算的。
- 一台稳定性推断器,照着 Compose 编译器的规则判类型稳不稳定,强跳过可以开关,两种结论当场对比。
- 一台协程调度器,用 generator 做真挂起点(
yield一次 = 一个挂起点)。Job 树、协作式取消、失败连坐、虚拟时钟、每个调度器有自己的线程时间线。主线程忙了多久 → 掉了几帧,是量出来的。 - 一整套 Flow。冷流是配方,操作符是套娃,背压是「什么都不加」的自然结果。
buffer/conflate/collectLatest走真的 Channel 和真的子协程取消,SharedFlow 的四个旋钮全部实现。 - 一台生命周期状态机,量出「切到后台的那几秒,你的收集器白跑了多少次」。
- 一台 CPS 变换器,把一小段
suspend函数真的切成状态机,连要塞几个L$字段都是做活跃变量分析算出来的。
从第 1 章到第 24 章,所有内容都在回答同一个问题的三个部分。它们在全书里有固定的颜色:
- 活下来——
remember、rememberSaveable、ViewModel、replay、slot 表里的那一格 - 重跑——重组、冷流被重新收集、
LaunchedEffect因为 key 变了而重启 - 取消——Job 被掐、
onDispose触发、collectLatest掐掉上一个、订阅归零
再加三个辅助色:挂起、流、跳过。代码块里也是这六个颜色,全书一致。
这本书写给
- 能写出 Compose 界面,但说不清「这一下会重跑哪些东西」的人
- 被
@Stable/@Immutable/强跳过绕晕过的人 - 知道
launch和collect怎么写,但没想过「取消到底怎么生效」的人 - 做过性能优化,但每次都靠「加个
remember试试」的人
这本书不讲
- Kotlin 语法入门——需要的语言点在用到的地方补,系统的进阶去看《坩埚》
- 并发的一般原理(线程、锁、事件循环)——那是《同时》
- 项目分层、DI、Navigation 3、模块划分——那是《承重》
- Material 3 的组件怎么用、动画怎么调参
六卷
重跑
R E R U N记住
K E E P挂起
S U S P E N D流动
F L O W接缝
S E A M落地
S H I P怎么读这本书
按顺序读。这本书不是参考手册,六卷是一条链子:卷 I 建立「重跑」这个模型,卷 II 说清楚「谁引起重跑」,卷 III、IV 把同一套逻辑搬到协程和 Flow 上,卷 V 是三者缝在一起的地方——也是线上事故最集中的地方,卷 VI 把前面全部换成可执行的改法。
每一章都先点 demo,再读字。这本书的所有关键数字都是网页里那六台引擎算出来的,不是我写上去的。你可以拨滑杆、点按钮,看数字怎么变——很多时候,把滑杆拉到两个极端比读三段解释管用。
赶时间的话:第 1、4、6、11、13、19、22 章是全书的骨架,七章读完,前面列的那四个 bug 你就都能自己定位了。
书里的代码按 Kotlin 2.4 + Compose 编译器(Kotlin 插件形态)写,强跳过默认开启(自 Compose 编译器 2.0.20 起就是默认值)。协程按 kotlinx.coroutines 1.10.x 的行为描述。
凡是和版本强相关的结论,正文里都会标出来。写作时间是 2026 年 8 月——如果你在更晚的时候读到这里,API 名字可能变了,但「什么时候重跑」这件事不会变:它是这套设计的地基,不是某一版的实现细节。