13
10

More than 3 years have passed since last update.

【Android】Retrofit2.6で追加されたCoroutine対応について

Last updated at Posted at 2020-01-06

はじめに

Retrofitがバージョン2.6でKotlin Coroutinessuspend関数に対応しました。

公式にCoroutineに対応した事によって、より簡単に非同期処理を実装できるようになりました。
ここではsuspend関数を使わない場合と使った場合の実装の違いを比較していきます。

リポジトリ

こちらに全体のコードを置いておきます。

準備(折りたたんでいます)

今回は https://api.github.com/repos/octocat/Hello-World からidとnameを取得します。

data class

まずGitHubのリポジトリを取得するためのクラスReposを作ります。
簡略化のためプロパティの数を絞っています。

Repos
data class Repos(
    val id: Int,
    val name: String
)

Retrofit

Retrofitのインスタンス生成処理を記載します。
リポジトリではOkHttp3も使っていますが本筋ではないので割愛します。

ApiService
class ApiService {

    private fun getRetrofit(): Retrofit {
        val moshi = Moshi.Builder()
            .add(KotlinJsonAdapterFactory())
            .build()
        return Retrofit.Builder()
            .baseUrl("https://api.github.com/")
            .addConverterFactory(MoshiConverterFactory.create(moshi))
            .build()
    }

    fun get(): GithubApi {
        val retrofit = getRetrofit()
        return retrofit.create(GithubApi::class.java)
    }
}

2020/01/07追記
JakeWharton氏曰く「Gson is deprecated.」との事だったので、GsonからMoshiに変更しました。

suspend関数を使わない場合

suspend関数を使わない場合のAPIの実装は以下になります。

GithubApi
interface GithubApi {
    @GET("/repos/octocat/Hello-World")
    fun getRepos(): Call<Repos>
}

Reposをリクエスト結果を返すCallオブジェクトでラップしています。
リクエスト結果をenqueueを使ってコールバックで受け取ります。

    fun getRepos() {
        private val api = ApiService().get()
        api.getRepos().enqueue(object : Callback<Repos> {
            override fun onResponse(call: Call<Repos>, response: Response<Repos>) {
                // 成功時の処理
            }

            override fun onFailure(call: Call<Repos>, t: Throwable) {
                // 失敗時の処理
            }
        })
    }

suspend関数を使う場合

GithubApi
interface GithubApi {
    @GET("/repos/octocat/Hello-World")
    suspend fun getReposWithCoroutine(): Repos
}

suspend関数を使う場合は関数の定義をsuspend funとします。
また、Callでラップせず、Reposをそのまま返すようにします。

取得処理は下記のようになります。

    fun getReposWithCoroutine() {
        private val api = ApiService().get()
        viewModelScope.launch {
            try {
                val repos = api.getReposWithCoroutine()
                // 成功時の処理
            }
            catch (e: Exception) {
                // 失敗時の処理
            }
        }
    }

コールバックを使わずにtry-catchでAPIリクエストを行えるため、コードがスッキリしました。

TIPS:viewModelScopeについて

今回は取得処理をViewModelで行ったため、ここではviewModelScopeを使っています。

viewModelScopeはViewModelとライフサイクルが一致しており、onCleared()で自動的にジョブをキャンセルしてくれるため、自分でCoroutineのライフサイクルを意識する必要がないという利点があります。

viewModelScopeを使わず、Activityなどで処理する場合は

CoroutineScope(Dispatchers.Main).launch {
    ...
}

のようになるかと思います。

おわりに

本記事を書くにあたり、以下のリンク先を参考にさせて頂きました。

【アクトインディ開発者ブログ】Retrofit + Kotlin Coroutines
【Qiita】Retrofit 2.6で通信を非同期処理

13
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
10