18 | 实战:让KtHttp支持挂起函数
朱涛
在上一次实战课当中,我们已经开发出了两个版本的 KtHttp,1.0 版本的是基于命令式风格的,2.0 版本的是基于函数式风格的。其中 2.0 版本的代码风格,跟我们平时工作写的代码风格很不一样,之前我也说了,这主要是因为业界对 Kotlin 函数式编程接纳度并不高,所以这节课的代码,我们将基于 1.0 版本的代码继续改造。这样,也能让课程的内容更接地气一些,甚至你都可以借鉴今天写代码的思路,复用到实际的 Android 或者后端开发中去。
跟往常一样,这节课的代码还是会分为两个版本:
3.0 版本,在之前 1.0 版本的基础上,扩展出异步请求的能力。
4.0 版本,进一步扩展异步请求的能力,让它支持挂起函数。
好,接下来就正式开始吧!
3.0 版本:支持异步(Call)
有了上一次实战课的基础,这节课就会轻松一些了。关于动态代理、注解、反射之类的知识不会牵涉太多,我们今天主要把精力都集中在协程上来。不过,在正式开始写协程代码之前,我们需要先让 KtHttp 支持异步请求,也就是 Callback 请求。
这是为什么呢?别忘了第 15 讲的内容:挂起函数本质就是 Callback!所以,为了让 KtHttp 支持挂起函数,我们可以采用迂回的策略,让它先支持 Callback。在之前 1.0、2.0 版本的代码中,KtHttp 是只支持同步请求的,你可能对异步同步还有些懵,我带你来看个例子吧。
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
本文介绍了KtHttp实战课程,重点讲解了网络请求框架的进化过程以及如何使网络请求框架支持挂起函数。作者详细介绍了KtHttp 3.0版本的开发过程,扩展了异步请求的能力,并支持了Callback请求。通过引入Callback接口和KtCall类,实现了异步请求的方式,使得KtHttp可以处理异步请求并在请求结果返回时调用相应的回调函数。同时,文章还介绍了如何让KtHttp同时支持同步和异步请求方式,通过对接口方法返回值类型的判断,实现了对不同请求方式的兼容性处理。此外,文章还介绍了如何在KtHttp中实现挂起函数的功能,以及两种解决方案:扩展KtCall和改动SDK内部。通过示例代码和详细解释,读者可以了解如何使用suspendCoroutine{}和suspendCancellableCoroutine{}来实现挂起函数,以及如何避免不必要的挂起和节省计算机资源。这篇实战教程对于想要深入了解网络请求框架实现细节的读者来说,是一篇值得阅读的文章。
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《朱涛 · Kotlin 编程第一课》,新⼈⾸单¥59
《朱涛 · Kotlin 编程第一课》,新⼈⾸单¥59
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(14)
- 最新
- 精选
- 迩、卜懂莪Kthttp系列实战 像是简易版的retrofit2 对学习 retrofit的源码有很大帮助
作者回复: 是的,Retrofit2也是练手的绝佳案例。
2022-03-154 - 神秘嘉Bin思考题: (1)执行async可认为一瞬间就到了suspendCancellableCoroutine的await扩展方法,即协程被挂起。 (2)执行deferred.cancel(),可以使得挂起函数立刻返回并抛出协程cancel异常 (3)协程取消了,但网络请求还是发出去了,(因为网络请求有自己的线程)也会回来,调用continuation.resume,发现协程被取消了,抛出协程已经被取消的异常 (4.1)网络IO比deferred.await()早,那么deferred.await()会拿到异常,并catch (4.2)网络IO比deferred.await()晚,那么deferred.await()会立刻返回,没有异常 以上都是我猜的,没有实际运行 -.-
作者回复: 分析很好。其实,能够直接分析出协程代码的执行流程,并且说出具体的原因,这也是很重要的一种能力。
2022-03-0233 - 荒原KtHttpV3.invoke()方法返回值这样写会将同步请求的返回值转成了一个异步的KtCall return if (isKtCallReturn(method)){ KtCall<T>( client.newCall(request), gson, getTypeArgument(method) ) }else{ val response = client.newCall(request).execute() //这里转成了一个KtCall对象 gson.fromJson( response.body?.string(), method.genericReturnType ) } 而这样写就不会 if (isKtCallReturn(method)){ return KtCall<T>( client.newCall(request), gson, getTypeArgument(method) ) }else{ val response = client.newCall(request).execute() return gson.fromJson( response.body?.string(), method.genericReturnType ) } 这是为什么呢
作者回复: 请问你这里同步、异步的判断依据是什么呢?说实话,我没看出来以上两段代码区别在哪里,只是换了return 的位置,理论上不应该影响逻辑的。你能提供一些具体的信息吗?
2022-05-211 - 王安泽请问为什么Async的写法response返回后程序没有结束呢?
作者回复: 没有立即结束,是因为Async底层使用的线程池没有立即回收,需要等一小会才会结束。
2022-04-141 - better第一,它可以避免不必要的挂起,提升运行效率 ;请问老师,这一条指的是? 思考题: 网络请求还是会执行,第一点避免了,但是二点没有避免。
作者回复: 是的。
2022-02-241 - Allen问题二:像 suspendCoroutine 这一类系统所提供的挂起函数底层到底实现了什么,才使得其具有挂起的功能?是内部自己实现了 Callback 吗?为啥我们自己实现的 suspend 函数必须调用系统提供的挂起函数才能生效?
作者回复: 这个问题有点深,在这里说不清,等到源码篇以后,你自己就懂啦~
2022-02-231 - Allen涛哥,问两个问题哈。如果上面例子中的网络请求是运行在当前线程,是不是这里的挂起实际上也没有什么用,因为其还是会阻塞当前线程(像下面的代码一样)? suspend fun testSuspendFunc() { suspendCancellableCoroutine<Unit> { // stimulate the network request Thread.sleep(5000) it.resumeWith(Result.success(Unit)) } }
作者回复: 是的。
2022-02-23 - Allen思考题的执行结果和 suspendCoroutine 的执行结果是一样的。取消了监听 invokeOnCancellation 的方法后,suspendCancellableoroutine 和 suspendCoroutine 本质上是一回事。
作者回复: 你实际运行然后仔细对比看看,是不是一点差别都没有?
2022-02-233 - 梦佳已经实践于项目,协程包装原来网络请求,一行代码获取数据2024-03-09归属地:上海
- jack思考题的运行结果参考: Time cancel: 697 invokeOnCompletion! Time exception: 702 Catch exception:kotlinx.coroutines.JobCancellationException: DeferredCoroutine was cancelled; job=DeferredCoroutine{Cancelled}@25084a1e Time total: 703 Request success!2023-10-13归属地:中国香港
收起评论