Retrofit を Coroutines と共に使ってみる
Jul 10, 2018 23:11 · 1230 words · 3 minute read
先日、Kotlin の Coroutines が Experimental でなくなったと聞いて、これは本格導入の機運だなと思ったのでひとまず Retrofit + RxKotlin を置き換えようと試みてみました。
そこで、ざっくりとした導入方法と、Jake 謹製の Coroutines 用 Retrofit アダプタの実装についてつらつらと書いてみたいと思います。
Retrofit で Coroutines
Retrofit に Deferred を 扱うためのアダプタを設定する
build.gradle (module)
:
dependencies {
implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-experimental-adapter:x.y.z'
}
RetrofitUtil.kt
:
object RetrofitUtil {
lateinit var retrofit: Retrofit
fun init(context: Context) {
retrofit = Retrofit.Builder()
.addCallAdapterFactory(CoroutineCallAdapterFactory()) // これで Retrofit で Deferred が使えるようになる
.baseUrl("...")
.client(createOkHttpClient(context))
.build()
}
private fun createOkHttpClient(context: Context): OkHttpClient =
OkHttpClient.Builder().build()
}
Deferred で通信結果を受ける
Fuga.kt
:
data class Fuga(
val piyoList: List<Piyo>
) {
data class Piyo(
val id: Long,
val name: String,
val height: Float
)
}
HogeService.kt
:
interface HogeService {
@GET("/fuga")
fun getFuga(): Deferred<Fuga>
}
HogeClient.kt
:
class HogeClient(private val retrofit: Retrofit = RetrofitUtil.retrofit) {
suspend fun getPiyoList(): List<Piyo> =
retrofit.create(HogeService::class.java) // Deferred<Fuga>
.await() // Fuga
.piyo // Fuga.piyo (List<Piyo>)
}
これだけ?
これだけです。
これだけで Deferred
で通信結果を受けられるようになる。すごい。
あなたも実装が気になってきたはずです。私は気になった。それでは見ていきましょう。
Kotlin Coroutine (Experimental) Adapter の実装を覗いてみる
めっちゃ薄い
このアダプタの実装は、150行足らずの1つのクラスにまとまっています。気持ちいいくらい薄いですね。
ほんのり解説
まず、Retrofit のアダプタなのでretrofit2.CallAdapter.Factory()
を継承し、その中でさらにDeferred<T>
が欲しい時用のCallAdapter
とDeferred<retrofit2.Response<T>>
が欲しい時用のCallAdapter
をそれぞれ定義しています。
要求された型がDeferred
のジェネリクスでない場合はnull
で早期リターンします。
また、要求された型がDeferred
であるがそのデータ型が指定されていない場合には例外を吐きます。
そこを抜けると後はDeferred<T>
が欲しいのかDeferred<Response<T>>
が欲しいのかの判定を行い、それぞれのCallAdapter
に渡します。
いずれのCallAdapter
も実装はほとんど同じです。
まずCompletableDeferred
のインスタンスを作り、このDeferred
がキャンセルされた際に通信もキャンセルするためにCompletableDeferred#invokeOnCompletion
にCall#cancel()
を記述します。
そして、Call#enqueue
を実行し、コールバックとして、失敗時にはCompletableDeferred#completeExceptionally(Throwable)
を、成功時にはCompletableDeferred#complete(T)
を呼びます。
最後にこうして出来上がったDeferred
をreturn
して完了です。
まとめ
非同期処理を完結に記述できる Coroutines 。
薄くて使い勝手の良いライブラリのおかげで今すぐにでも Retrofit と組み合わせて使えますね。
リアクティブプログラミング的なことをしたい場合は同じく Coroutines のChannel
を使って非同期処理をラップしてあげると良いかもしれません。
それでは。