suspendCancellableCoroutine 是 Kotlin 协程提供的一个底层挂起函数,用于将基于回调的异步 API 封装为挂起函数,同时支持协程的取消机制 。它比 suspendCoroutine 更强大,因为它允许在协程被取消时清理资源或停止正在进行的操作。
1. 作用
- 桥接回调式 API :将传统的回调(如
onSuccess/onFailure)转换为挂起函数,让调用方可以用同步风格写异步代码。 - 响应取消 :当启动协程的协程作用域被取消时,
suspendCancellableCoroutine可以感知取消事件,并执行清理操作(如关闭网络连接、取消异步任务),避免资源泄漏。
2. 函数签名
kotlin
suspend fun <T> suspendCancellableCoroutine(
block: (CancellableContinuation<T>) -> Unit
): T
- 它挂起当前协程,直到通过
continuation.resume(...)或continuation.resumeWithException(...)恢复。 - 参数
block接收一个CancellableContinuation<T>对象,该对象除了提供resume方法外,还增加了取消相关的功能。
3. 与 suspendCoroutine 的区别
| 特性 | suspendCoroutine |
suspendCancellableCoroutine |
|---|---|---|
| 取消监听 | ❌ 无法感知协程取消 | ✅ 可以注册取消回调 |
| 资源清理 | ❌ 需要手动处理(如用 finally) |
✅ 在取消回调中安全释放资源 |
| 并发处理 | 基础功能 | 额外提供原子性操作(如 invokeOnCancellation) |
4. 典型用法
示例:将回调式 API 封装为挂起函数
假设有一个基于回调的网络请求:
kotlin
interface Callback {
fun onSuccess(result: String)
fun onFailure(error: Throwable)
}
fun makeRequest(callback: Callback) {
// 模拟异步请求
Thread.sleep(1000)
callback.onSuccess("Data")
}
使用 suspendCancellableCoroutine 封装:
kotlin
suspend fun fetchData(): String = suspendCancellableCoroutine { continuation ->
makeRequest(object : Callback {
override fun onSuccess(result: String) {
// 恢复协程,返回结果
continuation.resume(result)
}
override fun onFailure(error: Throwable) {
// 恢复协程并抛出异常
continuation.resumeWithException(error)
}
})
// 注册取消回调:如果协程被取消,可以取消请求
continuation.invokeOnCancellation {
// 清理资源,例如取消网络请求、关闭流等
cancelRequest()
}
}
取消处理的关键点
invokeOnCancellation:注册一个回调,当协程被取消时执行。通常在这里释放资源或取消底层操作。- 如果底层 API 本身支持取消(如返回一个
Cancellable对象),可以在这里调用其取消方法。
5. 注意事项
- 原子性恢复 :
CancellableContinuation提供了resume的原子性保证,但开发者仍需确保不要重复调用resume。 - 已取消状态的检查 :在调用
resume前,可以使用continuation.isActive判断协程是否仍处于活跃状态,避免不必要的操作。 - 取消传播 :如果协程被取消,挂起点会抛出
CancellationException,调用方需要适当处理(通常由上层协程作用域统一处理)。
6. 高级功能
- 不可取消的挂起 :如果确实不需要取消,或者无法响应取消,可以使用
suspendCoroutine。但通常推荐使用suspendCancellableCoroutine以提供更好的协作式取消。 - 调用栈信息 :
CancellableContinuation还保留了挂起点的调用栈,便于调试。
总结
suspendCancellableCoroutine 是编写自定义挂起函数的核心工具,尤其适用于需要与取消机制协同工作的回调式 API。通过它,你可以将任何异步操作无缝集成到 Kotlin 协程的取消体系中,实现资源的安全管理和高效的并发控制。