[Android] RetrofitとRxJavaでRESTクライアントを実装する

Retforitは、Androidなどで使えるHttpクライアントです。Squareが開発しています。このRetrofitとRxJavaを組み合わせると、APIへのアクセスがシンプルに実装できていい感じです。今回は、RetrofitとRxJavaを用いて、RESTクライアントを実装してみます。REST APIとして、GitHub APIを使います。

パーミッションの追加

まずはインターネットにアクセスするためのパーミッションを追加します。プロジェクトのAndroidManifest.xmlを開き、uses-permissionにINTERNETを指定します。これでインターネットに接続するためのパーミッションを得られます。マニフェストファイルはこんな感じになります。

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

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

    <application
            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>

ライブラリの追加

次に、使用するライブラリをapp/build.gradleに追加します。使用するのは、上から、Retrofit、RetrofitとRxJavaを組み合わせて使うためのアダプター、Jsonのパーサであるmoshi、RxJava、RxJavaをAndroidで使いやすくするためのRxAndroidです。これらのライブラリを用いることで、極めてシンプルにRESTクライアントの実装を行うことが可能です。

dependencies {
    // Retrofit
    implementation 'com.squareup.retrofit2:retrofit:2.5.0'
    implementation "com.squareup.retrofit2:adapter-rxjava2:2.5.0"
    implementation "com.squareup.retrofit2:converter-moshi:2.5.0"

    // RxJava
    implementation 'io.reactivex.rxjava2:rxjava:2.2.5'

    // RxAndroid
    implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
}

エンティティの定義

APIから返ってくるJsonの形式に合わせて、エンティティを定義します。実際には必要な箇所のみ定義すれば良いと思いますが、今回は頑張ってたくさん定義しました。ここでは、Kotlinのデータクラスを使っています。

data class User(
    val login: String,
    val id: Int,
    val avatar_url: String,
    val gravatar_id: String,
    val url: String,
    val html_url: String,
    val followers_url: String,
    val following_url: String,
    val gists_url: String,
    val starred_url: String,
    val subscriptions_url: String,
    val organizations_url: String,
    val repos_url: String,
    val events_url: String,
    val received_events_url: String,
    val type: String,
    val site_admin: Boolean,
    val name: String,
    val company: String,
    val blog: String,
    val location: String,
    val email: String,
    val hireable: Boolean,
    val bio: String,
    val public_repos: Int,
    val public_gists: Int,
    val followers: Int,
    val following: Int,
    val created_at: String,
    val updated_at: String
)

エンドポイントの定義

インターフェースを用いて、エンドポイントを定義します。ここでは、アノテーションを用いてGETやPOST、PATCHなどを設定することが可能です。今回は、GETを使って、/users/{username}というパスでAPIにアクセスします。{username}部分は@Path(“username”)としている部分で引数として渡すことが可能です。ここではわかりやすくObservableを使っていますが、Singleを使った方が良さそうです。

interface GitHubClient {
    @GET("/users/{username}")
    fun getUser(@Path("username") username: String) : Observable<User>
}

Retforitを使ってAPIをコールする

ここまでできたら、Retrofitのインスタンスを生成します。#addConverterFactoryでJsonパーサとしてmoshiを使うことを指定しています。moshiは、Kotlinと相性の良いパーサです。また、#addCallAdapterFactoryでRxJavaのアダプターを使うことを指定しています。この指定を追加することで、RxJavaを経由してAPI通信の結果を受け取ることができます。

val retrofit = Retrofit.Builder()
    .baseUrl("https://api.github.com")
    .addConverterFactory(MoshiConverterFactory.create())
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .build()

実際にAPIにアクセスする箇所がここです。RetrofitとRxJavaを組み合わせています。API通信は別スレッドで行い、また返ってきた結果をメインスレッドで処理するように指定しています。メインスレッドで通信しようとするとアプリが落ち、またメインスレッド以外でビューの操作をしようとしてもアプリが落ちるので、この指定が重要です。このコードでは省略していますが、エラーが返ってきた時の処理も追加しておきたいですね。

disposable = retrofit.create(GitHubClient::class.java)
    .getUser("okuzawats")
    .subscribeOn(Schedulers.newThread())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe { user ->
        Log.d(TAG, user.login)
        Log.d(TAG, user.location)
        Log.d(TAG, user.bio)
    }

以上で、RetrofitとRxJavaを用いてGitHubのAPIにアクセスすることができました。さらにdisposableの処理などが必要となりますので、実際に実装する場合には以下のコード全文を参考にしていただければと思います。

コード全文

private const val TAG = "MainActivity"

class MainActivity : AppCompatActivity() {

    private var disposable: Disposable? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val retrofit = Retrofit.Builder()
            .baseUrl("https://api.github.com")
            .addConverterFactory(MoshiConverterFactory.create())
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .build()

        disposable = retrofit.create(GitHubClient::class.java)
            .getUser("okuzawats")
            .subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe { user ->
                Log.d(TAG, user.login)
                Log.d(TAG, user.location)
                Log.d(TAG, user.bio)
            }
    }

    override fun onDestroy() {
        super.onDestroy()

        disposable?.dispose()
        disposable = null
    }
}

GitHubに今回のコードを公開しておきました。

関連記事

KotlinのコルーチンとRetrofitでRESTクライアントを作るサンプルを作りました。