Android Kotlin基礎講座 08.1:インターネットからデータを取得する

Android Kotlin基礎講座

タスク:Retrofitでウェブサービスに接続する

火星の不動産データはRESTウェブサービスとして、ウェブサーバー上に保存されています。RESTアーキテクチャを使用しているウェブサービスは標準ウェブコンポーネントとプロトコルを使って構築されています。

標準化されたURIを用いて標準化された方法でウェブサービスへのリクエストを送信します。馴染みのあるウェブURLというのは、実際にはURIの型で、この講座では両方を同じ意味で使用します。例えば、この記事のアプリでは、以下のサーバーからデータを取得します。

https://android-kotlin-fun-mars-server.appspot.com

以下のURLをブラウザに打ち込むと、入手可能な実際の火星の不動産のリストが入手できます。

https://android-kotlin-fun-mars-server.appspot.com/realestate

ウェブサービスからの応答は一般的に、構造化データを表す交換形式であるJSON形式になっています。JSONについては次のタスクでより詳しく学習しますが、簡単な説明としては、JSONオブジェクトはキーと値がペアになっているコレクションで、ディクショナリやハッシュマップ、または連想配列と呼ばれることもあります。JSONオブジェクトのコレクションはJSON配列であり、ウェブサービスからの応答として返ってきた配列ということになります。

このデータをアプリに取得させるためには、ネットワークコネクションを構築し、サーバーとやり取りし、それから返ってきたデータを受け取り、アプリが使える形式にパースする必要があります。この記事では、RetrofitというRESTクライアントライブラリを使って、この接続を作っていきます。

ステップ1:Retrofitの依存関係をGradleに追加する

  1. build.gradle(Module:app)を開いてください。
  2. dpendenciesセクションに、Retrofitライブラリ用の以下のコードを追加してください。
implementation "com.squareup.retrofit2:retrofit:$version_retrofit"implementation "com.squareup.retrofit2:converter-scalars:$version_retrofit"

バージョン番号がプロジェクトのGradleファイルに切り離されて定義されていることを確認してください。最初の依存関係はRetrofit2ライブラリそのもの用で、二つ目はRetrofitスカラーコンバーター用です。このコンバーターによってJSONの結果をStringとして返すことができるようになります。これら二つのライブラリは合わせて動作します。

  1. 新し依存関係が作用するようにするために、Sync Nowをクリックしてください。

ステップ2:Java 8のサポートを追加する

Retrofit2を含むサードパーティライブラリの多くはJava 8言語の特徴を取り入れています。Android Gradleプラグインには特定のJava 8言語の特色に対応するための組み込みサポートが準備されています。これらを利用するためには、以下のようにモジュールレベルのbuild.gradleファイルをアップデートします。

android {
  ...

  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }
  
  kotlinOptions {
    jvmTarget = JavaVersion.VERSION_1_8.toString()
  }
}

ステップ3:MarsApiServiceを実装する

Retrofitはウェブサービスからのコンテンツに基づいて、アプリ用のネットワークAPIを作成します。
これはデータをウェブサービスから読み込み、それをデータをデコードする別のコンバーターライブラリに渡し、実際に使えるオブジェクト形式で返します。RetrofitにはXMLやJSONのような人気のウェブデータフォーマット用の組み込みサポートが含まれています。Retrofitはバックグラウンドスレッドでリクエストを走らせるなどといった重要な細かい部分を含む、ネットワークレイヤーのほとんどを作成してくれます。

MarsApiServiceクラスはアプリ用のネットワークレイヤーを保持します。つまり、これがViewModelがウェブサービスと通信するために使うAPIということです。このクラスにRetrofitサービスAPIを実装します。

  1. app/java/network/MarsApiService.ktを開いてください。現在このファイルにはウェブサービス用のベースURL用の定数のみが含まれています。
private const val BASE_URL = 
   "https://android-kotlin-fun-mars-server.appspot.com"
  1. 定数のすぐ下に、Retrofitビルダーを使って、Retrofitオブジェクトを作成してください。
    要求されたらretrofit2.Retrofitとretrofit2.converter.scalars.ScalarsConverterFactoryをインポートしてください。
private val retrofit = Retrofit.Builder()
   .addConverterFactory(ScalarsConverterFactory.create())
   .baseUrl(BASE_URL)
   .build()

RetrofitはウェブサービスAPIを構築するために、最低でも二つのものを必要とします。ウェブサービス用のベースURIと、コンバーターファクトリーです。コンバーターはRetrofitにウェブサービスから得たデータで何をすべきかを伝えます。今回の場合は、RetrofitにウェブサービスからJSONを読み取って、それをStringとして返してもらいたいということになります。

RetrofitにはStringと他のプリミティブ型をサポートするScalarsConverterがあるのでScalarsConverterFactoryのインスタンスを用いて、ビルダー上でaddConverterFactory()を呼び出します。最後に、build()を呼び出し、Retrofitオブジェクトを作成します。

  1. Retrofitビルダーの呼び出しのすぐ下で、HTTPリクエストを使ってRetrofitがウェブサーバーに呼びかける方法を定義するインターフェースを定義してください。要求されたらretrofit2.http.GETとretrofit2.Callをインポートしてください。
interface MarsApiService {
    @GET("realestate")
    fun getProperties():
            Call<String>
}

これで目指すところはウェブサービスからのJSONのstringを取得することだけとなりました。それをするのに必要なのはgetProperties()というメソッドただ一つだけです。Retrofitにこのメソッドが何をすべきかを伝えるために、@GETアノテーションを使い、そのウェブサービスメソッド用のパス、またはエンドポイントを指定します。
今回の場合は、エンドポイントはrealestateとします。getProperties()メソッドが呼び出されると、RetrofitはエンドポイントであるrealestateをベースURL(Retrofitビルダーに定義したもの)に追加し、Callオブジェクトを作成します。Callオブジェクトはリクエストを開始するために使われます。

  1. marsApiServiceインターフェースの下に、MarsApiというpublicなオブジェクトを作成し、Retrofitサービスを初期化してください。
object MarsApi {
    val retrofitService : MarsApiService by lazy { 
       retrofit.create(MarsApiService::class.java) }
}

Retrofitのcreate()メソッドはMarsApizServiceインターフェースを用いて、Retrofitサービスそのものを作成します。この呼び出しは負荷がかかるので、アプリは一つだけRetrofitサービスインタスタンスを必要とし、MarsApiというpublicなオブジェクトを使うことで、アプリの他の部分にもサービスを公開します。また、ここえはRetrofitサービスはlazyで初期化します。

これで全てのセットアップはできました。アプリがMarsApi.retrofitServiceを呼び出す度に、MarsApiServiceを実装しているシングルトンのRetrofitオブジェクトを取得します。

ステップ4:OverviewViewModelでウェブサービスを呼び出す

  1. app/java/overview/OverviewViewModel.ktを開いてください。
    getMarsRealEstateProperties()メソッドまでスクロールしてください。
private fun getMarsRealEstateProperties() {
   _response.value = "Set the Mars API Response here!"
}

これはRetrofitサービスを呼び出し、JSON stringを処理、返すメソッドです。現在のところ、結果用のプレースホルダーstringしかありません。

  1. responseに”Set the Mars API Response here!”と設定しているプレースホルダーの行を削除してください。
  2. getMarsRealEstateProperties()の中に、以下のコードを追加してください。
    要求されたらretrofit2.Callbackとcom.example.android.marsrealestate.network.MarsApiをインポートしてください。

MarsApi.retrofitService.getProperties()メソッドはCallオブジェクトを返します。そのオブジェクト上でenqueue()を呼び出し、バックグラウンドスレッドでネットワークリクエストを開始させます。

MarsApi.retrofitService.getProperties().enqueue( 
   object: Callback<String> {
})
  1. 赤いアンダーラインが引かれたobjectという単語をクリックしてください。
    Code > Implement methodsを選択してください。リストからonResponse()とonFailure()の両方を選択してください。

Android Studioによって、それぞれのメソッドにTODOが入ったコードを追加されます。

override fun onFailure(call: Call<String>, t: Throwable) {
       TODO("not implemented") 
}

override fun onResponse(call: Call<String>, 
   response: Response<String>) {
       TODO("not implemented") 
}
  1. onFailure()の中のTODOを削除し、_responseに読み込みが失敗した場合のメッセージを以下のように設定してください。
    _responseはテキストビューに表示される内容を決めるLiveData Stringです。それぞれの場合で_response LiveDataは更新される必要があります。

onFailure()コールバックはウェブサービスの結果が失敗だった際に呼び出されます。この結果用に、_responseにThrowable引数からのメッセージを連結させた”Failure: ”を設定します。

override fun onFailure(call: Call<String>, t: Throwable) {
   _response.value = "Failure: " + t.message
}
  1. onResponse()中のTODOを削除し、_responseにresponse.bodyを設定してください。
    onResponse()コールバックはリクエストが成功し、ウェブサービスが結果を返した場合に呼び出されます。
override fun onResponse(call: Call<String>, 
   response: Response<String>) {
      _response.value = response.body()
}

ステップ5:インターネットの許可を定義する

  1. コンパイルして、MarsRealEstateアプリを起動してください。エラーが表示され、アプリがすぐに閉じてしまうことを確認してください。

  2. Android StudioのLogcatタブをクリックし、以下のようなログ中のエラーを確認してください。
Process: com.example.android.marsrealestate, PID: 10646
java.lang.SecurityException: Permission denied (missing INTERNET permission?)

このエラーメッセージはアプリにINTERNETのパーミッション(許可)がないことを意味しています。インターネットに接続することにはセキュリティ上の懸念もあるので、デフォルトではアプリにはインターネットの接続が許可されていません。
明示的にAndroidにこのアプリがインターネットに接続する必要があることを伝える必要があります。

  1. app/manifests/AndroidManifest.xmlを開いてください。以下のコードを<application>タグの前に追加してください。
<uses-permission android:name="android.permission.INTERNET" />
  1. もう一度コンパイルしてアプリを起動してください。全てが正常に動作し、インターネット接続がされている場合は、火星の物件データを含むJSONテキストが表示されます。

  2. 実機、またはエミュレーターの戻るボタンをタップし、アプリを閉じてください。
  3. 実機、またはエミュレーターを機内モードにし、最近開いたアプリからもう一度アプリを開くか、Android Studioからアプリをリスタートさせてください。
  1. 機内モードをもう一度オフにしてください。

プロフィール

プロフィール
コードラボJP

大学卒業後SEに就職、現在は退職しフリーランスとして活動中。
『初心者でも挫折せずに一人でプログラミングを学べる』をモットーに、コードラボJPを開設
お問い合わせ等はcodelabsjp@gmail.comまで

コードラボJPをフォローする
タイトルとURLをコピーしました