SupervisorJob:别让一个子协程的失败连累全家

默认情况下,协程作用域用 Job(),父子关系是“一根绳上的蚂蚱”:任意一个子协程抛异常,整个作用域(包括其他正常运行的兄弟协程)都会被取消。对于“加载多条测线、其中一条失败不该影响其他”的场景,这太脆了。

换成 SupervisorJob(),子协程的失败不会向上传播,其他兄弟照常跑:

class RadarViewModel {
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
}

@PreDestroy:组件销毁时取消作用域

协程如果不主动取消,它会一直挂着,引用着 ViewModel / UI,造成内存泄漏,甚至组件销毁后还去刷新已经无效的 UI。把 scope 的取消绑到生命周期上:

@PreDestroy
fun onDestroy() {
scope.cancel() // 取消所有子协程
}

Mutex + 超时:防并发覆盖和死等

共有 / 复合病害的计算可能在短时间内被多次触发(连续编辑),如果不加锁,两个并发计算会互相覆盖结果。用 Mutex 互斥,保证同一时刻只有一个在算:

private val mutex = Mutex()

suspend fun recalc() = withTimeoutOrNull(60_000) {
mutex.withLock {
// 计算...
}
}
// 超时返回 null,降级处理,避免无限等待卡死

withTimeout(60s) 是兜底:万一锁被长期占用(比如某个计算卡死),不会让调用方无限等下去,超时就降级。

小结

协程工程化的三件套:SupervisorJob 隔离失败、生命周期绑定取消防泄漏、Mutex + 超时防并发覆盖。这三点配齐,协程在生产环境才稳。