Kolin协程与Retrofit 2.6.1完美合璧

协程有多么好用相比我们不需要再多赘述了,协程如何搭配旧版本的 Retrofit 使用相比大家也在网上看到过很多文章,大致如下:

//扩展 await() 函数
    private suspend fun <T> Call<T>.await(): T {
        return suspendCancellableCoroutine { continuation ->
            //await()的实质是调用 call的异步enqueue
            enqueue(object : Callback<T> {
                //请求失败
                override fun onFailure(call: Call<T>, t: Throwable) {
                    if (continuation.isCancelled) return // ②  //如果协程已经取消了,无需继续抛出异常
                    continuation.resumeWithException(t)
                }
                //请求成功
                override fun onResponse(call: Call<T>, response: Response<T>) {
                    //1.3版本的新特性 使用 resumeWith(Result<T>)
                    continuation.resumeWith(runCatching { // ①
                        if (response.isSuccessful) {
                            response.body()
                                ?: throw NullPointerException("Response body is null: $response")
                        } else {
                            throw HttpException(response)
                        }
                    })
                }
            })

            //当协程取消时的回调函数,协程取消  -  请求取消
            continuation.invokeOnCancellation {
                try {
                    cancel()
                } catch (ex: Throwable) {  // ③
                    //Ignore cancel exception
                    //此时协程已经取消,请求取消是否存在异常已经没有影响了
                }
            }
        }
    }

即,定义一个 Call 的扩展函数 await,挂起当前协程,执行 Call 的 enqueue 函数,在成功回调中 resume 协程,在失败回调中抛出异常。

现在不需要这么麻烦啦,只要使用最新版本的 Retrofit 2.6+ 版本,天然支持协程,网络请求如同同步方法一样易于书写。

New: Support suspend modifier on functions for Kotlin! This allows you to express the asynchrony of HTTP requests in an idiomatic fashion for the language.

@GET("users/{id}")
suspend fun user(@Path("id") id: Long): User

Behind the scenes this behaves as if defined as fun user(…): Call and then invoked with Call.enqueue. You can also return Response for access to the response metadata.

现在你只需要在你的网络请求方法前添加 suspend 修饰符,即可畅享协程带来的便利。在幕后实现方式与上边我们提到的方式大同小异,返回值可以是反序列化后的对象,也可以是 Response < T > ,以方便我们访问响应元数据。

实战:

try {
    val response = ServiceCreator.create(PlaceService::class.java).login()
    tv_detail.text = response
} catch (e: Throwable) {
    e.printStackTrace()
}

整个网络请求看起来就像是在执行同步方法一样,更加简洁易读!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章