PirateService
RESTful API 接口昨天已經實作完 https://pokeapi.co/api/v2/pokemon?offset=0&limit=10 的 API 接口,因此今天就接續昨天,快快的把 https://pokeapi.co/api/v2/pokemon/1 API 接口實作完
@GET("pokemon/{id}")
suspend fun fetchPirateInfo(@Path("id") name: String): Call<PirateInfo>
PirateInfo Data Class
先到 data/model
下建立 PirateInfo.kt
,PirateInfo
Data class 預期會存
根據這些需求,我們可以開出以下 data class
的規格,其中因為沒有攻擊的數據,因此把 base_experience
當作是攻擊數據
@JsonClass(generateAdapter = true)
data class PirateInfo(
@field:Json(name = "id") val id: Int,
@field:Json(name = "name") val name: String,
@field:Json(name = "height") val height: Int,
@field:Json(name = "weight") val weight: Int,
@field:Json(name = "base_experience") val attack: Int
) {
fun getIdString(): String = String.format("#%03d", id)
fun getWeightString(): String = String.format("%.1f KG", weight.toFloat() / 10)
fun getHeightString(): String = String.format("%.1f M", height.toFloat() / 10)
fun getAttackString(): String = "$attack/$maxAttack"
companion object {
const val maxAttack = 1000
}
}
上面的 Code 除了有取得 Json 資料之外,還使用到了之前有提過的 String Template
來 Format 字串
到這邊接口的部份已經可以取得多個 Pirate
回來,並且還可以取得特定的 Pirate
資訊回來,接下來是要建立 Repository
來統一數據的出入口
Sandwich
重構 PirateService
因為打 API 是屬於異步( Asynchronous )的範圍,因此如果自己要處理就要考慮到 Theard
或 Routine
的管理,不然可能會發生程式執行順序不對或是 Race Condition
的問題
那在研究 Pokedex 時,發現了作者寫了一個專門處理 Retrofit
Request/Response 的 Library ,因此決定導入
Sandwish 的出發點是從 ApiResponse
開始,他是一個會依據 Retrofit 的 Response 狀態,給予相對應處理的 Interface
看到 Source code 裡面,可以看到 ApiResponse
是一個 sealed class
Class 裡面分成
sealed class ApiResponse<out T> {
data class Success<T>(val response: Response<T>) : ApiResponse<T>() {
...
}
sealed class Failure<T> {
data class Error<T>(val response: Response<T>) : ApiResponse<T>() {
...
}
data class Exception<T>(val exception: Throwable) : ApiResponse<T>() {
...
}
透過這樣的方式,在處理 Response 上會更加準確與定義問題
另外,Sandwish
也很貼心的提供 Success
、 Error
與 Exception
的 suspend function
,在處理 Async 問題上可以多一種選擇
sandwich
加到 dependencies
// Sandwitch
implementation "com.github.skydoves:sandwich:1.0.4"
PirateService
接口的 Response Value
原本的 Return 格式是 Call
,那這邊就是把 Call
用 ApiResponse
取代
@GET("pokemon")
fun fetchPirateList(
@Query("limit") limit: Int = 10,
@Query("offset") offset: Int = 0
): ApiResponse<PirateResponse>
@GET("pokemon/{id}")
suspend fun fetchPirateInfo(
@Path("id") name: String
): ApiResponse<PirateInfo>
fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
return Retrofit.Builder()
.client(okHttpClient)
.baseUrl("https://pokeapi.co/api/v2/")
.addConverterFactory(MoshiConverterFactory.create())
.addCallAdapterFactory(CoroutinesResponseCallAdapterFactory())
.build()
}
今天補完了昨天沒完成的部份,並且簡單介紹了 Sandwich
這個專門處理 Retorfit
的 Library ,今天完成的量比較少,因為明天要講到 MVVM 的部份,算是比較複雜且需要比較詳細介紹的部份,因此想留到明天在一次介紹會比較完整