Retrofit 2.6.0 ! 更快捷的協程體驗 !

秉心說TM發表於2019-06-17

近日 Retrofit 更新到了 2.6.0 版本,內建了對 Kotlin Coroutines 的支援,進一步簡化了使用 Retrofit 和協程來進行網路請求的過程。其實縱觀程式語言的發展歷史,從彙編到 C/C++,從 Java,OC 到 Swift,Kotlin,甚至被納入教材的 Python,都有一個共同的特點。隨著 CPU 效能的越來越強悍,提高生產力似乎都成了現代高階程式語言的共同目標。Kotlin 就是一個好例子,做同樣的事情,完成同樣的功能,Java 的確需要更多的程式碼,Kotlin 也的確給 Android 開發提升了效率。特別是在非同步任務方面,Kotlin 提供了協程,而這是 Java 所不具備的。關於 Kotlin Coroutines 的介紹,可以閱讀我之前的三篇譯文:

在 Android 上使用協程(一):Getting The Background

在 Android 上使用協程(二):Getting started

在 Android 上使用協程(三) :Real Work

回到正題,本篇主要介紹 Retrofit 2.6.0 版本中協程的使用方式,不會過多涉及原理。我以我自己的 wanandroid 應用為例進行改造,原始碼中 Retrofit 版本是 2.4.0 。這個 wanandroid 是基於 Kotlin + 協程 + LiveData + MVVM 實現的,具體架構可見我的文章 真香!Kotlin+MVVM+LiveData+協程 打造 Wanandroid! ,個人覺得程式碼還是比較清晰的,很適合作為 Kotlin 的 入門專案。

老版本 Retrofit 的使用

在介紹如何使用 Retrofit 2.6.0 之前,我們先來看一下老版本的 Retrofit 是如何基於 Kotlin Coroutines 工作的,以登入介面為例。

首先在 WanService 介面中作如下定義:

@POST("/user/login")
fun login(@Field("username") userName: String, 
          @Field("password") passWord: String): Deferred<WanResponse<User>>
複製程式碼

注意這裡使用的返回值是 Deferred<T> 物件,這就意味著使用的時候要通過 await 來獲取返回值。那麼如何讓 Retrofit 直接返回 Deferred<T> 呢?使用的也是 JakeWharton 的開源庫:

implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
複製程式碼

在構建 Client 的時候新增上這個介面卡:

...
.addCallAdapterFactory(CoroutineCallAdapterFactory.invoke())
...
複製程式碼

然後給 LoginRepository 提供一個 suspend 方法:

suspend fun login(userName: String, passWord: String): WanResponse<User> {
    return apiCall { WanRetrofitClient.service.login(userName, passWord).await() }
}
複製程式碼

這裡使用 await 來獲取 Deferred<T> 的返回值。

最後在 LoginViewModel 中是這樣呼叫的:

fun login(userName: String, passWord: String) {
    launch {
        val response = withContext(Dispatchers.IO) { repository.login(userName, passWord) }
        executeResponse(response, { mLoginUser.value = response.data }, { errMsg.value = response.errorMsg })
    }
}
複製程式碼

launch() 方法做了簡單的封裝,感興趣的同學可以到原始碼中看一下。

以上就是在 Retrofit 2.4.0 中使用協程的基本方式了,其實程式碼也很簡潔。而 Retrofit 2.6.0 讓這一切更加簡單!就讓我們一睹為快吧!

Retrofit 2.6.0 中協程的使用

Talking is cheap, show me the code ! 還是上面的登入介面,基於 Retrofit 2.6.0 來改造一下。

第一步,修改 Retrofit 依賴。

implementation 'com.squareup.retrofit2:retrofit:2.6.0'
複製程式碼

第二步,修改 WanService 中介面的定義。

@POST("/user/login")
suspend fun login(@Field("username") userName: String, 
                  @Field("password") passWord: String): WanResponse<User>
複製程式碼

看到區別了嗎?首先,不再返回 Deferred<T> 物件,而是直接返回我們需要的 WanResponse 物件。其次,使用了 suspend 來修改方法,標記這是掛起函式。

第三步,修改 LoginRepository 中方法定義。

suspend fun login(userName: String, passWord: String): WanResponse<User> {
    return apiCall { WanRetrofitClient.service.login(userName, passWord) }
}
複製程式碼

與之前的版本相比,這裡不需要呼叫 await 方法了。其實並不是不呼叫了,而是 Retrofit 幫助我們自動呼叫了。

最後別忘了去除之前新增的 kotlin-coroutines-adapter,因為我們不再需要人工返回 Deferred<T> 物件,也不再需要手動呼叫 await 了。

...
//.addCallAdapterFactory(CoroutineCallAdapterFactory.invoke())
...
複製程式碼

至此,基於 Retrofit 2.6.0 版本的改造就已經完成了。我的 Wanandroid 專案已經完成全部修改,具體修改內容可見 commit

總結

隨著 Kotlin 成為 Android 開發的首選語言,越來越多的新特性都將在 Kotlin 上優先實現。協程作為 Kotlin 的非同步利器,很值得我們學習。如果你還沒有入手,那麼,從我的 Wanandroid 開始吧 !

文章首發微信公眾號: 秉心說 , 專注 Java 、 Android 原創知識分享,LeetCode 題解。

更多相關知識,掃碼關注我吧!

Retrofit 2.6.0 ! 更快捷的協程體驗 !

相關文章