通过协程将异步调用转换为同步调用且添加请求超时策略
·
/**
* 通过协程将异步调用转换为同步调用且添加请求超时策略
*/
fun testAsync2Sync() {
//runBlocking会阻塞当前线程
Log.i(TAG, "testAsync2Sync() 00");
runBlocking {
val job = launch {//协程作用域内启动新的获取数据协程,不会阻塞当前线程
try {
//方式1 使用可取消挂起函数处理耗时操作
val data = fetchDataCancellable()
Log.i(TAG, "testAsync2Sync() 11 launch end Result: $data")
//方式2 使用简单挂起函数处理耗时操作
//fetchDataSimple()
} catch (e: CancellationException) {
Log.i(TAG, "testAsync2Sync() 12 Coroutine cancelled")
} catch (e: Exception) {
Log.i(TAG, "testAsync2Sync() 13 Error: ${e.message}")
}
}
//如果fetchData异步骤请求超时则取消获取数据协程,job中会收到CancellationException回调
val timeoutJob = launch { //超时处理协程,如果fetchData超时了则取消获取数据协程
Log.i(TAG, "testAsync2Sync() 22");
delay(2000) // 模拟一段时间后取消
job.cancel() // 取消协程
Log.i(TAG, "testAsync2Sync() 33");
}
job.join()//等待子协程完成
Log.i(TAG, "testAsync2Sync() 44 timeoutJob.isActive:${timeoutJob.isActive}");
if(timeoutJob.isActive) { //如果异步接口获取未超时,则取消超时处理协程
timeoutJob.cancel()
}
Log.i(TAG, "testAsync2Sync() 55 runBlocking end")
}
}
// 异步接口定义
interface Callback {
fun onSuccess(data: String)
fun onError(error: Throwable)
}
// 子线程模拟异步函数
fun asyncFetchData(callback: Callback) {
thread {
Thread.sleep(1000)
Thread.currentThread()
callback.onSuccess("Data loaded ")
Log.i(TAG, "asyncFetchData() end currentThread: ${Thread.currentThread()}")
// 模拟错误: callback.onError(IOException("Network error"))
}
}
/**
* 挂起函数 suspendCancellableCoroutine 可用于 异步转同步,需手动处理回调、取消
* 在该函数中处理异步get监听,然后调用continuation.resume完成挂起函数
* launch中会等待 fetchData 返回,或者取消协程抛出CancellationException
* 或者异常抛出Exception
*/
suspend fun fetchDataCancellable(): String = suspendCancellableCoroutine { continuation ->
val callback = object : Callback {
override fun onSuccess(data: String) {
continuation.resume(data, null)
}
override fun onError(error: Throwable) {
continuation.resumeWithException(error)
}
}
Log.i(
TAG,
"fetchDataCancellable() 11 before call asyncFetchData currentThread: ${Thread.currentThread()}"
)
asyncFetchData(callback)
Log.i(TAG, "fetchDataCancellable() 22 after call asyncFetchData")
// 监听到调用job.cancel() 协程取消 做资源释放处理
continuation.invokeOnCancellation {
// 实际项目中应取消异步任务,例如关闭网络请求
// 此处无法真正取消线程,仅为示例
Log.i(TAG, "fetchDataCancellable() 33 OnCancellation")
}
}
/**
* 挂起函数 withContext(Dispatchers.IO) 显式切换线程上下文
* 可以用 isActive 状态判断协程是否取消。
*/
suspend fun fetchDataSimple(): String = withContext(Dispatchers.IO) {
Log.i(TAG, "fetchDataSimple() begin")
if (isActive) {
//delay作为协程原生挂起函数,会主动检查协程状态,取消时抛出 CancellationException
delay(5000)
//Thread.sleep是 Java 的线程阻塞方法,完全脱离协程控制机制,调用时协程无法感知取消事件
//Thread.sleep(5000)
}
Log.i(TAG, "fetchDataSimple() end currentThread: ${Thread.currentThread()}")
"success"
}
更多推荐


所有评论(0)