近日 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 題解。
更多相關知識,掃碼關注我吧!
