はじめてRetrofitを使ってみる (Android Kotlin)

/




Retrofitを使った説明はたくさんあるが、デザインパターンを埋め込んで説明しているものが多く、肝心のRetrofitの役割がどこからどこまでなのかイメージし辛く分かりづらかった。
そこで、MainActivity.ktファイルだけに必要なRetrofit関係のコードを書いていてみた。
最小限のサンプルではあるが、動作を理解する上ではとてもわかりやすくなった。



完成イメージ


Retrofitとは、APIから取得するJSONデータを、オブジェクトにしてアクセスできるようにするまでを面倒見てくれるHTTP clientだ
ここではRetrofitを使って、APIから拾ったデータを下の図のようにViewへ表示させるまでをやってみたいと思う。



いきなりだが全コードを記す。



以外に短くて、拍子抜けしたかもしれない。
なお、本サンプルはGithubへあげておいた。記事ページ下のリンクを参照されたし。
それでは手順を追って説明していく。


APIの準備


まず、自前のAPIを用意する。GithubやQiitaのような本格的なものではなく、もっとシンプルで単純なもののほうが理解を早めるからだ。それに、自分で作ったものなのでAPIの仕様を変更できるし興味もわく。

そういうことで、次のような内容のJSONファイルをサーバー上へ置いた。


URLはこのようになっている。http://apppppp.com/jojo.json


Retrofitの実装 (implementation)


Retrofitを使えるようにするため、新規プロジェクトのbuild.gradle (Module: app)に次のように追加する。


これは、retrofit2最新版と、GSON、そしてRetrofit用のGSONコンバーターを指定しているのだ。


データクラスの作成


JSONファイルの内容と合わせて、次のようなデータクラスを定義した。ただし、JSONのキーの名前とプロパティの名前は同じにすること。
data class JoJo(val name: String = "", val stand: String = "")


インタフェースの作成


次にインタフェースを作成する。
interface JoJoService {
    @GET("jojo.json")
    fun fetchJoJo(): Call<JoJo>
}

ドメイン以下のパスをGETアノテーションの引数に渡す。つまりこの場合だと、ドメイン直下にファイルを置いたのでjojo.jsonを渡せば良い。

fetchJoJoメソッドは、APIリクエストを行う。定義をするだけで、実装はやる必要はない。

なんと素晴らしいことに、Retrofixが実装をやってくれるのだ!
ところで、fetchJoJoメソッドで返されるCallオブジェクトは、 import retrofit2.Call でインポートしているものだ。一度どんなものか、仕様を見ておくと良いだろう。


MainActivity


最後にMainActivityクラスを見ていこう。

ここでは、Retrofitオブジェクトを次のようにして生成する。
val retrofit = Retrofit.Builder()
    .baseUrl("https://apppppp.com/")
    .addConverterFactory(GsonConverterFactory.create())
    .build()

注意してほしいのは addConverterFactory(GsonConverterFactory.create()) だ。
今回GSONを使用するので、このファクトリメソッドを設定しないとJSONをオブジェクトに変換できない。以下のようなエラーが出たら、ここを疑ってほしい。

java.lang.IllegalArgumentException: Unable to create converter for class com.apppppp.retrofitsample.JoJo
            for method JoJoService.fetchJoJo


それでは、先程のRetrofitオブジェクトを実際に使っていこう。メインスレッドでは実行できないので、thread内で実行していく。

retrofit.create(JoJoService::class.java)では、先ほど作ったインタフェースのクラスオブジェクトを渡している。

val handler = Handler()

thread { // Retrofitはメインスレッドで処理できない
    try {
        val service:JoJoService = retrofit.create(JoJoService::class.java)
        val jojo = service.fetchJoJo().execute().body() ?: throw IllegalStateException("bodyがnullだよ!")

		....

    } catch (e: Exception) {
        Log.d("mopi", "debug $e")
    }
}


スレッド内から、UIを更新したい場合はこのように記述する。
handler.post(Runnable {
    // メインスレッドで処理
    val nameTextView = findViewById<TextView>(R.id.name)
    val standTextView = findViewById<TextView>(R.id.stand)

    nameTextView.text = jojo.name
    standTextView.text = jojo.stand
})


以上でRetrofitを使ったサンプルコードの出来上がりだ。

おっと、忘れていた!次の記述がマニフェストに無いと、インターネットアクセス出来ないのでご注意を。
<uses-permission android:name="android.permission.INTERNET" />



関連記事


非同期 & ネットワーク処理
* はじめてRetrofitを使ってみる (Android Kotlin)
* 非同期処理でCoroutine(コルーチン)を使ってみる (Android Kotlin)
* OkHttpでHTTP通信 (Android Kotlin)
* スレッド処理 (Android Kotlin)

View & レイアウト
* リサイクラービューを使ってリスト表示 (Android Kotlin)
* 角丸表現 (Android Kotlin)
* onSaveInstanceStateで画面回転時の状態の保存と復元 (Android Kotlin)
* ListViewを簡単なモデルで理解しよう (Android Kotlin)
* バネアニメーション (Android Kotlin)
* startActivityForResultを使ってみる (Android Kotlin)
* ActivityとFragmentの連携を理解する (Android Kotlin)
* DataBinding機能を使ってみる (Android Kotlin)
* タッチイベントのフック (Android Kotlin)
* DialogFragmentを使ったダイアログの表示 (Android Kotlin)

サウンド
* これってSoundPoolのバグ?(Android Kotlin)
* SoundPoolを使ってゲームの効果音を再生する (Android Kotlin)

データ & オブジェクト
* Kotlinでオブジェクト(object)の動作確認
*
データクラスとタプル (Android Kotlin)
* Null安全、ぬるぽバイバイ (Android Kotlin)