〈kotlin〉Retrofit

Android studioでkotlinを使ってAndroidアプリ作成の勉強中。

Retrofit ライブラリを使用して、インターネット上の REST ウェブサービスに接続し、レスポンスを取得する。
以下の一連のcodelabを参考に勉強したので基本的な使い方をまとめる。
インターネットからデータを取得して表示する  |  Kotlin を用いた Android の基本 - インターネット - データを取得して表示する  |  Android Developers

依存関係の追加

implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation 'com.squareup.retrofit2:converter-moshi:2.9.0'
implementation "com.squareup.moshi:moshi-kotlin:1.12.0"

MoshiはJson文字列をkotlinオブジェクトに変換してくれる。
RetrofitはMoshiと連携するコンバータを持っている。
(コンバータはウェブサービスから返されたデータをどのように処理するか伝える役割)

権限の宣言

アプリがインターネットにアクセスするためにAndroidManifest.xmlに権限を追加する。

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

Jsonの戻り値を格納するデータクラスの作成

Jsonオブジェクトにはkey-valueペアが含まれており、これに対応したデータクラスを作成する。
Jsonのkeyを変数名、valueのデータ型を変数のデータ型として作成する。

data class MarsPhoto(
   val id: String, 
   val img_src: String
)

Jsonのkeyと異なる変数名を付けたい場合は、@Json アノテーションを使用する。

data class MarsPhoto(
   val id: String, 
   @Json(name = "img_src") val imgSrcUrl: String
)

Retrofitオブジェクトの作成

ベースURL

ベースURLを定数に入れておく。
このURLの後ろに、欲しい情報に対応したエンドポイントを追加することになる。

private const val BASE_URL = "https://android-kotlin-fun-mars-server.appspot.com"
Moshiオブジェクト
private val moshi = Moshi.Builder()
   .add(KotlinJsonAdapterFactory())
   .build()
Retrofitオブジェクト

上で作成したmoshiのインスタンスをコンバータファクトリとして渡し、
ベースURLを追加する。

private val retrofit = Retrofit.Builder()
   .addConverterFactory(MoshiConverterFactory.create(moshi))
   .baseUrl(BASE_URL)
   .build()

ウェブサーバーと通信する方法を定義するインターフェースの作成

HTTPメソッドを使用してサーバーへのリクエストを行う。

GET サーバーデータを取得する
POST または PUT サーバーに対して新しいデータの追加、作成、更新を行う
DELETE サーバーからデータを削除する

データを受け取るには@GETアノテーションを使用し、エンドポイントを指定する。
メソッドはコルーチンで使用できるようにsuspendにする。

interface MarsApiService {
    @GET("photos")
    suspend fun getPhotos():  List<MarsPhoto>
}

APIサービスをアプリの他の部分に公開

オブジェクト宣言を使用して Retrofit API サービスのインスタンスをシングルトンで宣言し、
アプリの他の部分で使用できるようにする。

object MarsApi {
    val retrofitService : MarsApiService by lazy {
       retrofit.create(MarsApiService::class.java) }
}

サービスを呼び出す

シングルトン オブジェクトMarsApiを使用して、
retrofitService インターフェースの getPhotos() メソッドを呼び出す。
サーバー接続時には例外が起こることがよくあるため、
アプリが突然終了しないようにtry-catchで例外処理を記述しておく。

class OverviewViewModel : ViewModel() {

   private val _status = MutableLiveData<MarsApiStatus>()
   val status: LiveData<MarsApiStatus> = _status

   private val _photos = MutableLiveData<List<MarsPhoto>>()
   val photos: LiveData<List<MarsPhoto>> = _photos

   init {
       getMarsPhotos()
   }

   private fun getMarsPhotos() {
        viewModelScope.launch {
            _status.value = MarsApiStatus.LOADING
            try {
                _photos.value = MarsApi.retrofitService.getPhotos()
                _status.value = MarsApiStatus.DONE
            } catch (e: Exception) {
                _status.value = MarsApiStatus.ERROR
                _photos.value = listOf()
            }
        }
    }
}