渐进式编程课
返回全部路线
跨平台开发

Kotlin Multiplatform

从共享源码集一路学到 Compose Multiplatform、ViewModel 与 Flow。

64

已归档课程

更新至 2026.09.30

课程目录

按顺序学习,也可以直接搜索

64 节课程
  1. 第 1 课KMP 源码集与代码共享Kotlin Multiplatform(KMP)让 Android、iOS 等平台共享业务代码,同时保留调用各平台原生 API 的能力。理解源码集,是后续学习网络请求、数据存储和 Compose Multiplatform 的基础。2026.07.17
  2. 第 2 课KMP 目标与 Gradle 配置KMP 不会自动决定要支持哪些平台。我们需要在共享模块的 Gradle 配置中声明 Android、iOS 等目标,Gradle 才知道同一份共享代码要编译成哪些平台产物。2026.07.18
  3. 第 3 课使用 expect/actual 对接平台能力共享业务有时需要读取系统版本、设备名称等平台信息。commonMain 不能直接调用 Android 或 iOS API,此时可以用 expect/actual 把平台差异隔离在对应源码集中。2026.07.19
  4. 第 4 课用 commonTest 测试共享逻辑共享代码会同时影响 Android 和 iOS,因此越接近业务核心,越应该先用测试固定行为。写在 commonTest 的测试可以随不同平台目标执行,避免为同一条业务规则重复写多套测试。2026.07.20
  5. 第 5 课KMP 共享协程基础网络请求、数据库读取等操作不会立即完成。KMP 可以在共享代码中用协程统一描述这些异步任务,让 Android 和 iOS 复用同一套业务流程。2026.07.21
  6. 第 6 课用 Flow 表达共享数据流一次网络请求通常返回一个结果,适合使用 suspend;行情、数据库列表、登录状态等数据会持续变化,更适合使用 Flow。KMP 可以在共享层定义数据流,再由 Android 和 iOS 观察同一套业务数据。2026.07.22
  7. 第 7 课用 StateFlow 管理共享状态页面通常既需要知道“当前值”,又需要持续接收后续变化,例如计数、登录状态和加载状态。StateFlow 同时具备当前值与数据流能力,适合由 KMP 共享层向 Android、iOS 暴露状态。2026.07.23
  8. 第 8 课Kotlin Serialization 共享序列化Android 和 iOS 调用同一个接口时,可以在共享层完成 JSON 解析,得到统一的 Kotlin 数据模型。这样两端不必各自维护一套字段映射规则。2026.07.24
  9. 第 9 课用 Ktor Client 发起共享网络请求Ktor Client 是支持 Kotlin Multiplatform 的异步 HTTP 客户端。请求与响应处理可以写在共享层,Android 和 iOS 只需要提供各自的平台网络引擎。2026.07.25
  10. 第 10 课用 Repository 组织共享数据层页面如果直接调用 Ktor API,就会同时依赖网络地址、JSON 字段和业务规则。Repository 位于数据层,对上提供业务需要的数据,对下调用网络或数据库,使平台 UI 不必了解数据来源细节。2026.07.26
  11. 第 11 课用密封类型表达数据结果网络请求不仅会成功,也可能出现断网、HTTP 状态异常或数据解析失败。共享层可以用密封类型把结果完整交给调用方,让 Android 和 iOS 对所有情况进行明确处理,而不是用空对象或 UI 占位状态掩盖错误。2026.07.27
  12. 第 12 课用构造器注入共享依赖如果一个类在内部直接创建 Ktor Client 或 Repository,它会与具体实现紧密绑定,测试时也必须访问真实网络。构造器依赖注入让外部决定使用真实实现还是测试替身,Android 和 iOS 也能按各自入口组装同一套共享业务。2026.07.28
  13. 第 13 课手动组装共享依赖构造器注入解决了“类如何接收依赖”,但仍需要一个地方创建真实的 Ktor Client、数据源、Repository 和用例。这个集中组装对象图的位置通常称为 Composition Root(组合根)。2026.07.29
  14. 第 14 课构建共享状态持有者Android 和 iOS 页面通常都要处理加载中、成功和失败。如果两端各自编写一套状态转换,行为容易不一致。可以在 commonMain 中建立状态持有者,把数据层结果转换为统一状态,再让平台 UI 负责渲染。2026.07.30
  15. 第 15 课测试共享状态持有者共享状态持有者决定 Android 和 iOS 最终看到的页面状态。把测试写在 commonTest,可以用一套用例验证两端共同依赖的状态转换,不需要启动模拟器或访问真实服务器。2026.07.31
  16. 第 16 课定义共享存储接口Android 与 iOS 都能保存少量偏好数据,但它们使用不同平台 API。共享业务不应直接依赖任一平台;先定义统一接口,平台源码集再提供具体实现。2026.08.01
  17. 第 17 课实现 Android 偏好存储上一课只定义了 PreferenceStorage 接口。Android 端需要把这个接口映射到真实的平台存储 API,才能让共享 LanguageRepository 保存和读取偏好。2026.08.02
  18. 第 18 课实现 iOS 偏好存储iOS 端需要为同一个 PreferenceStorage 接口提供实现。共享 LanguageRepository 因此可以保持不变,同时在 iPhone 和 iOS 模拟器上使用系统偏好存储。2026.08.03
  19. 第 19 课认识 Compose Multiplatform 共享 UIKMP 不仅可以共享数据层,也可以使用 Compose Multiplatform 共享 Android、iOS、桌面和 Web 的 UI 代码。共享组件接收数据并发送用户事件,平台入口负责把它显示到各自窗口中。2026.08.04
  20. 第 20 课把 StateFlow 接入共享 UI上一课的共享组件只能显示外部传入的静态参数。本课把 UserStore.state 接入 Compose,使 Repository 数据变化后,Android 和 iOS 的共享界面都能自动重新渲染。2026.08.05
  21. 第 21 课连接 Android 与 iOS 的 Compose 入口共享 @Composable 函数不会自己创建 Android 窗口或 iOS 控制器。每个平台仍需要一个很薄的原生入口,把共同的 App() 放进平台宿主中。2026.08.06
  22. 第 22 课Compose 共享资源与本地化把文案直接写在 Kotlin 代码里,会让翻译、地区适配和统一修改变得困难。Compose Multiplatform 可以在 commonMain 维护共享字符串资源,并根据设备语言自动选择对应翻译。2026.08.07
  23. 第 23 课Compose 共享图片资源Logo、插图和图标等跨平台一致的图片只维护一份,Android 与 iOS 界面都通过生成的 Res 访问它们。2026.08.08
  24. 第 24 课Compose 共享主题颜色、排版和形状集中定义后,共享组件不必到处写死样式;切换亮色或深色模式时也能整体保持一致。2026.08.09
  25. 第 25 课Compose 共享 UI 测试同一份测试可以确认共享 Composable 是否正确显示状态、响应点击,减少 Android 与 iOS 界面行为不一致的风险。2026.08.10
  26. 第 26 课Compose 共享页面导航Android 与 iOS 可以复用同一套路由、返回栈和页面跳转逻辑,不必分别维护首页到详情页的导航流程。2026.08.11
  27. 第 27 课Compose 类型安全路由传参从列表页打开详情页时,通常需要告诉详情页“打开哪一条数据”。把 id 放进路由后,Android 与 iOS 共用同一种参数格式,编译器也能检查参数类型。2026.08.12
  28. 第 28 课Compose 导航返回栈普通详情页需要返回上一页,而登录、支付完成等一次性流程结束后,不应该再返回旧页面。正确整理返回栈可以避免“登录成功后按返回键又看到登录页”。2026.08.13
  29. 第 29 课Compose 共享导航测试导航图写对并不代表按钮一定连到了正确页面。共享导航测试可以确认 Android 与 iOS 共用的 NavHost 在用户点击后确实显示目标页面。2026.08.14
  30. 第 30 课Compose 共享 ViewModel页面重组时不重复创建业务状态,并让 Android 与 iOS 共用同一份状态更新逻辑。2026.08.15
  31. 第 31 课StateFlow 生命周期感知收集页面进入活跃状态时开始收集数据,页面进入后台或离开活跃状态时停止收集,避免不可见界面继续做无意义的 UI 更新。2026.08.16
  32. 第 32 课ViewModel 读取路由参数详情页 ViewModel 可以直接获得 itemId 并向 Repository 加载数据,不需要让 Composable 解析参数后再层层传递。2026.08.17
  33. 第 33 课ViewModel 按 ID 加载数据详情页只需要接收一个 itemId,真正的数据读取由 ViewModel 和 Repository 完成;Android 与 iOS UI 只渲染加载、成功或失败状态。2026.08.18
  34. 第 34 课Repository Flow 转 StateFlow当本地数据库、缓存或网络数据持续变化时,详情页可以自动收到最新结果,不必每次都手动调用 load()。2026.08.19
  35. 第 35 课combine 合并多个 Flow一个详情页往往同时依赖商品信息和收藏状态。任意数据源发生变化时,页面都应重新计算并显示一致的最新结果。2026.08.20
  36. 第 36 课catch 转换 Flow 异常数据库读取或网络同步失败时,页面不会因为未处理异常而中断,而是稳定显示“加载失败”等错误内容。2026.08.21
  37. 第 37 课retryWhen 有限重试网络短暂中断等临时故障可能很快恢复。与其立即展示错误,可以先自动重试;同时限制次数并筛选异常类型,避免无限重试或掩盖程序错误。2026.08.22
  38. 第 38 课debounce 处理搜索输入用户输入搜索词时,每敲一个字符都会产生新值。如果立即查询,容易触发大量无效请求;debounce() 可以等用户短暂停顿后再继续处理。2026.08.24
  39. 第 39 课flatMapLatest 只保留最新搜索搜索词变化后,旧请求可能比新请求更晚返回,导致页面显示过期结果。flatMapLatest() 会切换到最新查询对应的 Flow,避免旧结果覆盖新结果。2026.08.25
  40. 第 40 课distinctUntilChanged 过滤重复输入搜索词经过 trim() 等处理后,不同的原始输入可能变成同一个值。过滤这些连续重复值,可以避免再次发起语义相同的搜索。2026.08.26
  41. 第 41 课onStart 发送加载状态搜索请求发出后、结果返回前,页面需要显示正在加载。把 Loading 也放进 Flow,可以让界面只渲染统一的 SearchUiState,不必额外维护加载开关。2026.08.27
  42. 第 42 课onEach 观察状态变化共享层常需要记录状态日志或调试数据流。onEach() 可以观察每个状态,同时保持原值不变,让 UI 继续消费同一条状态流。2026.08.28
  43. 第 43 课launchIn 启动 Flow 收集当共享层只需要执行日志、埋点等观察动作,不需要在 collect 代码块中处理值时,可以把 onEach() 与 launchIn() 组合成清晰的数据流管道。2026.08.31
  44. 第 44 课shareIn 共享上游 Flow多个观察者订阅昂贵的冷 Flow 时,可共享一次网络监听或数据源收集。2026.09.01
  45. 第 45 课状态流与事件流的语义选择避免把连续两次相同操作误当成同一份状态。2026.09.02
  46. 第 46 课SharedFlow订阅时机测试用确定的调度步骤验证晚订阅者不会收到 replay=0 的历史事件。2026.09.03
  47. 第 47 课WhileSubscribed停止时机测试验证最后一个订阅者离开后,上游是否按设定超时停止。2026.09.04
  48. 第 48 课replay缓存与重新订阅验证新订阅者能否收到最近缓存状态。2026.09.07
  49. 第 49 课resetReplayCache清空事件缓存在一次性事件已被处理后清空旧缓存,避免后续订阅者再次收到它。2026.09.08
  50. 第 50 课subscriptionCount观察订阅者观察共享流当前是否有活跃订阅者,为按需启动上游工作提供判断依据。2026.09.09
  51. 第 51 课订阅者驱动上游启停只在共享流有人订阅时运行昂贵的轮询任务。2026.09.10
  52. 第 52 课订阅状态去重启停命令避免订阅者数量变化但启停状态未变时重复执行命令。2026.09.11
  53. 第 53 课WhileSubscribed重启上游测试验证最后一个订阅者离开后,再次订阅会按策略重新启动上游。2026.09.14
  54. 第 54 课replayExpirationMillis清理回放订阅停止后按策略清除共享流的旧回放值。2026.09.15
  55. 第 55 课advanceTimeBy验证回放过期用虚拟时间精确推进 replayExpirationMillis 边界。2026.09.16
  56. 第 56 课runCurrent执行到期任务只执行当前虚拟时间点已排队的协程任务。2026.09.17
  57. 第 57 课advanceUntilIdle清空队列在协程测试中推进虚拟时间,直到没有待执行任务。2026.09.18
  58. 第 58 课对比runCurrent与advanceUntilIdle观察延迟任务在两个测试调度步骤后的状态。2026.09.21
  59. 第 59 课advanceTimeBy 推进部分虚拟时间不清空所有任务,只观察延迟任务到期前的中间状态。2026.09.22
  60. 第 60 课advanceTimeBy 检查边界任务测试延迟任务在指定毫秒到达前后是否执行。2026.09.23
  61. 第 61 课比较边界前一毫秒与到期时刻精确测试异步任务在截止时间前不会提前完成,并在截止时执行。2026.09.24
  62. 第 62 课验证多个延迟任务的执行顺序测试两个不同延迟的任务不会提前或乱序完成。2026.09.28
  63. 第 63 课记录延迟任务完成时刻在虚拟时间测试中记录每个任务的完成时刻。2026.09.29
  64. 第 64 课断言虚拟时间完成点在测试中把任务完成时刻变成可回归的断言。2026.09.30