SuperAPI AI 工具集

kotlin-coroutines

编程与开发

查看项目

更新于 10-16 00:20

技能介绍

用途:这份参考面向编写、评审或调试 Kotlin 协程代码的场景,建立在结构化并发之上:每个协程都运行在某个作用域中,取消与错误会沿父—子层级传播。资料聚焦两个最常出错的方面:谁拥有作用域,以及不破坏取消的异常处理。

主要能力与核心主张:主线程安全方面,执行阻塞工作的函数自己持有 withContext(ioDispatcher),调用方不应在调用挂起函数前切换调度器。作用域所有权上,优先写 suspend fun,让调用方拥有作用域;在非 UI 类(repository、manager、use case、data source)中存储 CoroutineScope 是强烈的评审信号,因为该类必须自证拥有取消、错误上报、重启和生命周期管理。

危险之处与替代方案:一旦存储的作用域被取消,之后所有 launch 都会静默地以取消完成,没有异常也没有日志。需要比调用方活得更久的工作,应交给 WorkManager 任务,或交给显式拥有作用域、有名字的应用级类(例如注入 applicationScope、仅在进程死亡时取消的 OfflineBookmarkQueue)。状态持有者在满足三个条件时才可以从不挂起的事件回调中 launch:确实拥有视图层收集的 UI 状态、使用生命周期绑定的作用域(viewModelScope / rememberCoroutineScope)、触发源是 UI 事件。

反模式与诊断:init { launch } 和 DI 单例构造器里的 launch 都让工作不可见,可改用 stateIn 暴露 StateFlow,或用 WorkManager.enqueueUniquePeriodicWork。诊断问题:启动时刻在哪定义、谁能观察它是否在运行、能否不重启进程就重启它。

取消与异常:在长循环顶部用 ensureActive(),用 isActive 检查而不抛出,yield() 额外让出线程;清理逻辑放在 finally { withContext(NonCancellable) { … } } 中。TimeoutCancellationException 属于 CancellationException,绝不能不重抛就捕获;网络超时交给 OkHttp/Retrofit/Ktor。只捕获具体类型(IOException、HttpException),不要捕获 Exception/Throwable;不要在挂起函数里用 runCatching,改用重抛 CancellationException 的 suspendRunCatching;try/catch 不会包住 launch {},要放进协程体内;supervisorScope 中未被 await 的 async {} 会吞掉异常;viewModelScope 已使用 SupervisorJob,不要再叠加。

KMP 与测试:不要用 MainScope(),它像 GlobalScope 一样是非结构化的;应从平台层注入生命周期绑定的 CoroutineScope 和 CoroutineDispatcher。协程与调度器测试见 android-skills:android-testing,注意两个调度器的陷阱(runTest + MainDispatcherRule 需共享同一调度器)以及 Compose 测试中 StandardTestDispatcher 的默认值。具体平台命令与安装方式暂未提供。