KotlinのCoroutinesでRetrofitをより便利に!

2017.06.19

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

まえがき

KotlinでAndrid開発は控えめにいって、 最高 です。

AndroidでAPIを叩く時には、OkHttp + Retrofit + RxJavaが定番になっていると思います。

Koltinの力を持ってすれば、RxJavaを使わず、Coroutinesを使うことで、幸せな開発が待っているかもしれません。

注意:Kotlin 1.1.xでは、Coroutinesは、experimental機能です。実験的な機能ですので、リリースされるまでは、プロダクトにいれないほうが無難です

RxJava版とCoroutines版の比較

もっとシンプルな具体例のほうがよかったけど、すいません。MVP構成での具体例になりました。。。

RxJava版

interface GithubApi {
    @GET("users/{user}")
    fun user(@Path("user") user: String): Single<User>
}
class GithubRepositoryImpl(val api: GithubApi) : GithubRepository {
    override fun user(user: String) = api.user(user)
}
class GithubPresenter(val view: GithubView, val repository: GithubRepository) {
    fun search(user: String) = repository.user(user)
            .subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe({
                if (it == null) {
                    view.notFoundUser()
                } else {
                    view.showUser("${it.id}:${it.name}")
                }
            }, {
                view.showError(it)
            })
}

Coroutines版

RetrofitをCoroutinesに変換してくれるライブラリがあります。

gildor/kotlin-coroutines-retrofit: Kotlin Coroutines await() extension for Retrofit Call

とても薄いCallの拡張関数です。

同期的な書き方でとてもみやすい。

interface GithubApi {
    @GET("users/{user}")
    fun user(@Path("user") user: String): Call<User>

}
class GithubRepositoryImpl(val api: GithubApi) : GithubRepository {
    override fun user(user: String) = async(CommonPool) {
        api.user(user).awaitResponse()
        // api.user(user).await() <- スタータスコードとか必要ないなら、これだけでも良い
    }
}
class GithubPresenter(val view: GithubView, val repository: GithubRepository) {
    fun search(user: String) = launch(UI) {
        try {
            val response = repository.user(user).await()
            if (response.body() == null) {
                view.notFoundUser()
                return@launch
            }
            response.body()?.run {
                view.showUser("$id:$name")
            }
        } catch (e: Throwable) {
            view.showError(e)
            e.printStackTrace()
        }
    }

}

まとめ

今回は1つAPIしか叩かなかったので、ぱっと見の違いがないのかもしれないですが、複数組み合わせてAPIを叩くときにはものすごい威力を発揮します。

備えよう! Coroutinesのリリースに!

サンプル:kamedon/KodeinSample