Kotlin-回调如何转成挂起函数
持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第 9 天,点击查看活动详情
前言
笔者在项目中开始使用 Kotlin 时还是 Java 和 Kotlin 混合的项目,所以对于一些 Java 库提供的回调接口,再使用 Java 的方式调用感觉使用了假的 Kotlin。
本文记录下笔者在使用 Kotlin 过程中,把 Java 回调转成挂起函数的过程,不止是 Java 回调,Kotlin 回调也是可以的。
单一回调方法
单一回调方法是最容易转成挂起函数的,以 Android 中常见的点击事件接口为例:
1 | // 自定义的View,代表Android中的View |
以上代码是对 Android 中点击事件的抽象,正常情况下,我们应该是以下面的形式调用 setOnClickListener
方法:
1 | fun main() { |
那我们怎么把 setOnClickListener
方法转成挂起函数呢?就是使用 Kotlin 提供的 suspendCoroutine
方法,suspendCoroutine
方法可以帮我们拿到当前协程的 Continuation
实例,笔者在 Kotlin-挂起函数挂起了啥? 中简单介绍了 suspendCoroutine
的实现。
下面让我们把回调转成挂起函数:
1 | suspend fun setOnClickListenerSuspend(): View { |
首先声明挂起方法 setOnClickListenerSuspend
返回值为回调方法中的入参类型 View,接着写挂起函数的方法体,直接调用 suspendCoroutine
返回,在 suspendCoroutine
的 block 中调用原来的 setOnClickListener
传入回调,最后在回调中调用 Continuation#resume
函数传入回调方法的View 类型的入参。
这样就完成了单一回调方法转成挂起函数,我们调用下试试,与原来回调的方式对比一下:
1 | // main方法增加suspend关键字 |
我们通过 suspendCoroutine
把单一回调方法转成了挂起函数,与原来回调的方式相比,代码顺序上是挂起函数是同步调用的形式,看起来更直观一些。
两个回调方法
两个回调方法我们常见的是 OkHttp 中的网络请求回调:
1 | data class Response(val value: String) |
正常情况下我们调用应该是这样的:
1 | fun main() { |
通过 object
关键字构造回调的匿名类然后传入 sendRequest
方法,现在我们仍然可以使用 suspendCoroutine
方法把 sendRequest
方法转成挂起函数:
1 | suspend fun sendRequestSuspend() = suspendCoroutine<Response> { continuation -> |
在 onFailure
方法中调用 Continuation#resumeWithException
函数抛出异常,在 onResponse
方法中还是调用 Continuation#resume
函数传入结果,我们对比下前后使用上的差异:
1 | suspend fun main() { |
使用挂起函数的方式,Continuation#resumeWithException
函数抛出的异常一般使用 try catch
捕获异常,调用方可以根据异常类型进行不同的处理逻辑。