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()
}

整個網絡請求看起來就像是在執行同步方法一樣,更加簡潔易讀!

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