〈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() } } } }