/**
     * 通过协程将异步调用转换为同步调用且添加请求超时策略
     */
    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"
    }

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐