Kotlin<协程>异步回调封装

目的

协程用起来很方便,可以将异步的代码完全平铺开,写成和同步一样的代码形式。但很多时候,很多方法是以回调的形式给出的,所以处理起来依旧不够优雅。
本篇文章的目的就是解决这个问题。

例子

原始形式

以OkHttp为例,OkHttp就是以回调的形式给出网络请求结果。通常我们的写法如下:

 /**
     * 原始写法
     */
    private fun okHttpTest() {
        client.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                Log.d(TAG, "onFailure: ${e.message}")
            }
            override fun onResponse(call: Call, response: Response) {
                Log.d(TAG, "onResponse: ${response.body()?.string()}")
                nextEvent(response.message())	//下一步事件
            }
        })
    }
    
    /**
     * 事件流事件
     */
    private fun nextEvent(event: String) {
        Log.d(TAG, "nextEvent: $event")
    }

这么写完,依旧没有摆脱回调地狱,而且依旧无法同时并行完成事件流。

改造回调

	/**
     * 改造后的写法
     */
    private suspend fun okHttpWithCoroutine(): Response = suspendCancellableCoroutine {
        client.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                it.resumeWithException(e)       //事件处理异常,协程回复,抛出异常
            }

            override fun onResponse(call: Call, response: Response) {
                it.resume(response)     //事件处理完毕,协程回复,返回结果
            }
        })
    }
		//改造后的使用
        scope.launch {
            val result = withContext(Dispatchers.IO) {  //子线程运行网络任务
                okHttpWithCoroutine().body()?.string()
            }   //在获取到结果之前,协程处于挂起状态,不会执行接下去的任务
            result?.let { nextEvent(it) }   //获取到结果,自动切换到主线程,执行下一步任务
        }

上述代码的改造方法,可简单总结为:在需要返回结果的地方,调用resume()方法;在需要抛出异常的地方,调用resumeWithException()方法。
如果nextEvent()方法也是回调式的,可以同样改造成这样方式。

改造普通函数变成挂起函数,最常用的两个函数是 suspendCoroutinesuspendCancellableCoroutine,这两者几乎大同小异,都是接受一个lambda表达式作为参数。区别是,前者传入的Continuation,后者传入的是CancellableContinuation<T>。后者可以执行continuation.invokeOnCancellation { }函数,该函数会在协程被取消时执行。可用于一些如资源需要关闭、或者网络请求等场景,实现在协程被取消时,关闭资源or取消网络请求。

优化:并行处理事件流

上面的方式,两个任务依旧不是同步执行的,而仍旧是按照顺序执行的,效率上并未得到提升,只是代码上看着舒服了一些。
如需并行执行,可配合async{}wait(),来同步执行两个任务。当两个任务都获取到结果后,再执行之后的任务。

scope.launch {
	val first = async {
		okHttpWithCoroutine().body()?.string()
	}
    val second = async {
        nextEvent()
    }
    Log.d(TAG, "sync result : ${first.await()} -- ${second.await()}")
}

参考:更优雅的使用回调函数 —— Kotlin 协程

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值