能否为协程设置超时挂起?需求类似suspendCoroutine的超时函数
实现带超时的
suspendCoroutine替代函数 当然可以实现这个需求!Kotlin协程框架其实已经给我们提供了现成的超时处理工具,我们只需要把它和suspendCoroutine结合起来,就能得到你想要的功能。
核心思路
核心逻辑就是用withTimeout(或withTimeoutOrNull)包裹suspendCoroutine调用——withTimeout会在指定时间内未完成时自动抛出超时异常,完美匹配你需要的"超时后抛出异常并继续执行"的需求。
具体实现代码
import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.withTimeout import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException import kotlin.coroutines.suspendCoroutine import java.util.concurrent.TimeoutException /** * 带超时的suspendCoroutine替代函数 * @param timeoutMillis 超时时间,单位毫秒 * @param block 回调逻辑块,用法与原生suspendCoroutine完全一致 * @throws TimeoutException 当回调未在超时时间内触发时抛出 */ suspend fun <T> suspendCoroutineWithTimeout( timeoutMillis: Long, block: (kotlin.coroutines.Continuation<T>) -> Unit ): T { return try { withTimeout(timeoutMillis) { suspendCoroutine(block) } } catch (e: TimeoutCancellationException) { // 将协程自带的取消异常转换为标准TimeoutException throw TimeoutException("Coroutine timed out after $timeoutMillis ms") } }
代码说明
withTimeout会创建一个限时作用域,若内部的suspendCoroutine未通过resume/resumeWithException完成,就会抛出TimeoutCancellationException- 我们捕获这个协程取消异常,转换为你需要的标准
TimeoutException(如果不需要转换,直接抛出原异常也可,它本身是TimeoutException的子类) - 传入的
block和原生suspendCoroutine用法完全一致,你可以像之前一样在回调里调用continuation.resume()或continuation.resumeWithException()
使用示例
模拟一个回调风格的异步API,测试超时场景:
// 模拟回调式异步函数 fun fetchRemoteData(callback: (Result<String>) -> Unit) { // 模拟2秒的耗时操作 Thread.sleep(2000) callback(Result.success("Loaded remote data successfully")) } // 测试带超时的协程函数 suspend fun main() { try { // 设置1.5秒超时,此时fetchRemoteData会超时 val data = suspendCoroutineWithTimeout(1500) { continuation -> fetchRemoteData { result -> result.fold( onSuccess = { continuation.resume(it) }, onFailure = { continuation.resumeWithException(it) } ) } } println(data) } catch (e: TimeoutException) { println("Request failed: ${e.message}") } }
运行这段代码会触发超时,控制台打印Request failed: Coroutine timed out after 1500 ms。
可选:超时返回null而非抛出异常
如果你希望超时后不抛出异常,而是返回null,可以用withTimeoutOrNull实现:
suspend fun <T> suspendCoroutineWithTimeoutOrNull( timeoutMillis: Long, block: (kotlin.coroutines.Continuation<T>) -> Unit ): T? { return withTimeoutOrNull(timeoutMillis) { suspendCoroutine(block) } }
这个版本在超时后返回null,你可以根据业务逻辑自行处理返回值,无需捕获异常。
注意事项
如果你的回调逻辑可能在超时后继续执行,建议添加一个标记判断协程是否已取消,避免重复调用resume导致异常。
内容的提问来源于stack exchange,提问作者usbpc102
相关产品推荐
相关产品推荐

