[Android] KotlinのコルーチンとRetrofitでRESTクライアントを実装する

遅ればせながらKotlinのコルーチンに入門しました。KotlinのコルーチンとRetrofitでREST APIにアクセスするという非常に簡単なことをやりたかったのですが、サンプルがなかなか見つからなかったり、見つかっても情報が古かったりして、動かすまでに一苦労しました。

何とかKotlinのコルーチンとRetrofitでREST APIにアクセスできるようになったので、雑なサンプルコードを置いておきます。コードは書き捨てだし、コルーチンについては浅い理解しかないので、あしからず。サンプルコードの全体はGitHubに公開しておくので、適宜ご参照ください。あくまで雑なコードですので、その点をよろしくお願いします。

app/build.gradle。Timberはログ出力に使います。

dependencies {
    // Coroutine
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1'

    // Retrofit2
    implementation 'com.squareup.retrofit2:retrofit:2.5.0'
    implementation 'com.squareup.retrofit2:converter-moshi:2.5.0'

    // Coroutine Adapter
    implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'

    // Timber
    implementation 'com.jakewharton.timber:timber:4.7.1'
}

Timberの初期化はカスタムのApplicationクラスで行います。

class MyApplication: Application() {
    override fun onCreate() {
        super.onCreate()

        if (BuildConfig.DEBUG) {
            Timber.plant(Timber.DebugTree())
        }
    }
}

マニフェストファイルでカスタムのApplicationクラスの登録とインターネットアクセスのパーミッションを取得します。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.okuzawats.retrofitwithcoroutine">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
            android:name=".MyApplication"
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

build.gradle。Kotlinのバージョンは1.3.20です。

buildscript {
    ext.kotlin_version = '1.3.20'
    repositories {
        google()
        jcenter()
        
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.3.1'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
        
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

エンティティはデータクラスで定義しました。

data class User(
    val id: String,
    val name: String,
    val avatar_url: String
)

Retrofitのインターフェースです。メソッドはコルーチンのDeferredを返します。

interface GitHubApi {
    @GET("users/{user_name}")
    fun fetchUser(@Path("user_name") userName: String): Deferred<User>
}

Retrofitのインスタンスを作ります。アダプタにCoroutineCallAdapterFactoryというものを使っています。

private fun getGitHubApi(): GitHubApi {
    return Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(MoshiConverterFactory.create())
        .addCallAdapterFactory(CoroutineCallAdapterFactory())
        .build()
        .create(GitHubApi::class.java)
}

あとはリクエストを作って、awaitで結果が返ってくるのを待ちます。

GlobalScope.launch(Dispatchers.Main) {
    val request = getGitHubApi().fetchUser("okuzawats")
    try {
        val response = request.await()

        Timber.i(response.id)
        Timber.i(response.name)
        Timber.i(response.avatar_url)
    } catch (e: Throwable) {
        Timber.e(e)
    }
}

これでOKです。

参考文献