RERUN · KEEP · SUSPEND · FLOW · SEAM · SHIP · 它什么时候重跑

重跑

R E R U N

你已经会写 Compose 了。界面出得来,数据也能刷新。然后有一天你发现:输入框里每敲一个字,整个列表都在重组;退出页面之后,那个上传任务还在后台跑了十几秒;切到后台四秒钟,行情收集器白算了四十次;旋转一下屏幕,Snackbar 又弹了一遍。

这些看上去是四个毫不相干的 bug。它们其实是同一个问题的四个侧面——你不知道你写的东西什么时候会被重跑,也不知道重跑的时候,谁该活下来、谁该被扔掉。

这本书的主线只有一句:你写的不是界面,是一个会被反复调用的函数。你要操心的从来不是「怎么跑一遍」,而是重跑的时候——什么活下来、什么重算、什么被取消

下面是同一个待办屏幕(13 个 composable 节点)上的三个改动,书里那台重组器当场算出来的:

这不是示意图。三行里的每一个数字,都是第 1 章那台重组器算出来的——它就在网页里跑,你可以自己点。

24
6
24个互动 Demo
6台真引擎:重组器 · 稳定性推断 · 协程调度器 · Flow · 生命周期 · CPS 变换

这本书为什么值得你花时间

讲 Compose 的材料已经很多了,但它们大多停在「怎么写」:用 remember 记住状态,用 LaunchedEffect 发请求,用 collectAsStateWithLifecycle 收流。这些你都会。

问题出在下一层:为什么这里要 remember,那里不用?为什么这个 key 写错了会重发请求?为什么 collectAsState 在后台还在跑?这些问题的答案不在 API 文档里,在运行时的行为里——而运行时的行为,只有看见了才记得住。

所以这本书里有六台真东西:

  • 一台带 slot 表的重组器。真的位置记忆、真的读取观察、真的失效传播、真的跳过。重组从失效的那个节点开始,不从根开始——书里所有「重跑几个」的数字都是它算的。
  • 一台稳定性推断器,照着 Compose 编译器的规则判类型稳不稳定,强跳过可以开关,两种结论当场对比。
  • 一台协程调度器,用 generator 做真挂起点(yield 一次 = 一个挂起点)。Job 树、协作式取消、失败连坐、虚拟时钟、每个调度器有自己的线程时间线。主线程忙了多久 → 掉了几帧,是量出来的。
  • 一整套 Flow。冷流是配方,操作符是套娃,背压是「什么都不加」的自然结果。bufferconflatecollectLatest 走真的 Channel 和真的子协程取消,SharedFlow 的四个旋钮全部实现。
  • 一台生命周期状态机,量出「切到后台的那几秒,你的收集器白跑了多少次」。
  • 一台 CPS 变换器,把一小段 suspend 函数真的切成状态机,连要塞几个 L$ 字段都是做活跃变量分析算出来的。
◆ 全书的三个动词

从第 1 章到第 24 章,所有内容都在回答同一个问题的三个部分。它们在全书里有固定的颜色:

  • 活下来——rememberrememberSaveableViewModelreplay、slot 表里的那一格
  • 重跑——重组、冷流被重新收集、LaunchedEffect 因为 key 变了而重启
  • 取消——Job 被掐、onDispose 触发、collectLatest 掐掉上一个、订阅归零

再加三个辅助色:挂起跳过。代码块里也是这六个颜色,全书一致。

这本书写给

  • 能写出 Compose 界面,但说不清「这一下会重跑哪些东西」的人
  • @Stable@Immutable/强跳过绕晕过的人
  • 知道 launchcollect 怎么写,但没想过「取消到底怎么生效」的人
  • 做过性能优化,但每次都靠「加个 remember 试试」的人

这本书不讲

  • Kotlin 语法入门——需要的语言点在用到的地方补,系统的进阶去看《坩埚》
  • 并发的一般原理(线程、锁、事件循环)——那是《同时》
  • 项目分层、DI、Navigation 3、模块划分——那是《承重》
  • Material 3 的组件怎么用、动画怎么调参

六卷

卷 I

重跑

R E R U N
你写的不是界面,是一个会被反复调用的函数
卷 II

记住

K E E P
State 是「被人盯着的格子」,而不同的东西活的时长不一样
卷 III

挂起

S U S P E N D
协程:一棵会连坐的树,和一个必须你自己检查的取消
卷 IV

流动

F L O W
Flow:一段配方、一层套娃、一次关于谁等谁的谈判
卷 V

接缝

S E A M
Compose × 协程 × 生命周期,三样东西缝在一起的地方
卷 VI

落地

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 名字可能变了,但「什么时候重跑」这件事不会变:它是这套设计的地基,不是某一版的实现细节。