Retrofit in Android

現在Retrofit 超重要的,以前都使用原始的okhttp 自己轉換json.

但業界作法是用Retrofit, 所以這技能是一定要會的,所以今天我就親自來實作看看.

什麼是Retrofit ?

Retrofit is type-safe REST client for Android and Java which aims to make it easier to consume RESTful web services. 

It makes it relatively easy to retrieve and upload JSON via a REST based webservice. 

In Retrofit you configure which converter is used for the data serialization. 

Typically for JSON you use GSon, but you can add custom converters to process XML or other protocols. 

Retrofit uses the OkHttp library for HTTP requests

----

Retrofit vs Volley?

Retrofit is a purely abstract layer above okhttp used for network calls and it takes away the boiler plate required for writing those lengthy AsynTasks.

So, Retrofit is just another library like Volley, EasyNetwork but it has support for integrating with RxAndroid as well as live data classes from Android Architecture.

Retrofit is not related to Java programming..
It is related to Android concepts ..

Retrofit is a REST Client for Java and Android. It makes it relatively easy to retrieve and upload JSON (or other structured data) via a REST based webservice. In Retrofit you configure which converter is used for the data serialization. Typically for JSON you use GSon, but you can add custom converters to process XML or other protocols. Retrofit uses the OkHttp library for HTTP requests

-----

參考資料 more information:

https://ithelp.ithome.com.tw/articles/10246733

https://ithelp.ithome.com.tw/articles/10253382

---

Retrofit 案例實作:

step 1: create basis kotlin project.

implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'

Add 網路權限AndroidManifest.xml

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

step 2:  data class(JSON) via JsonToKotlinClass轉換

data class WeatherData(
val records: Records,
val result: Result,
val success: String
)

data class Records(
val datasetDescription: String,
val location: List<Location>
)

data class Result(
val fields: List<Field>,
val resource_id: String
)

data class Location(
val locationName: String,
val weatherElement: List<WeatherElement>
)

data class WeatherElement(
val elementName: String,
val time: List<Time>
)

data class Time(
val endTime: String,
val parameter: Parameter,
val startTime: String
)

data class Parameter(
val parameterName: String,
val parameterUnit: String,
val parameterValue: String
)

data class Field(
val id: String,
val type: String
)

step3: create  interface WeatherApiService.kt

定義與 API 符合的 Interface,這是 Retrofit 的最大賣點.

private val BASE_URL = "https://opendata.cwb.gov.tw/api/"

interface WeatherApiService {
@GET("v1/rest/datastore/F-C0032-001")
fun getWeather(
@Query("Authorization") key: String,
@Query("locationName") city: String? = null
): Call<WeatherData>
}

object WeatherApi {
private val retrofit = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(BASE_URL)
.build()

val retrofitService: WeatherApiService = retrofit.create(WeatherApiService::class.java)
}

PS: 幾個重點

1.宣告爲object單例

2.建立請求: api有多種常見請求方式@GET,@POST,@PUT,@DELETE等等

3.以@Query註解的參數key,city.

呼叫getWeather()時.將授權碼(key),城市名(city)作爲引數傳進去,再與GET,@Query的參數一起合併爲完整可取得api的網址.

4.因city宣告爲? , null可選,如果要用可傳入例如city="嘉義縣",這樣就只拿到嘉義縣的部分.

5.呼叫.enqueue異步發起請求.

-----

step 4: create function call in main activity.

WeatherApi.retrofitService
.getWeather(key = Constant.CWB_KEY)
.enqueue(object : retrofit2.Callback<WeatherData> {
override fun onFailure(call: Call<WeatherData>, t: Throwable) {
Log.e("fail", t.message.toString())
}

override fun onResponse(
call: Call<WeatherData>, response: Response<WeatherData>
) {
//api response..
Log.d("success", response.toString())

if (response.isSuccessful) {
response.body()?.records?.location?.forEach {
Log.d("api", it.toString())
}
}
}
})

---

output:

2022-06-20 12:25:24.855 6550-6550/com.example.myapplication1 D/api: Location(locationName=金門縣, weatherElement=[WeatherElement(elementName=Wx, time=[Time(endTime=2022-06-20 18:00:00, parameter=Parameter(parameterName=多雲時晴, parameterUnit=null, parameterValue=3), startTime=2022-06-20 12:00:00), Time(endTime=2022-06-21 06:00:00, parameter=Parameter(parameterName=晴時多雲, parameterUnit=null, parameterValue=2), startTime=2022-06-20 18:00:00), Time(endTime=2022-06-21 18:00:00, parameter=Parameter(parameterName=晴時多雲, parameterUnit=null, parameterValue=2), startTime=2022-06-21 06:00:00)]), WeatherElement(elementName=PoP, time=[Time(endTime=2022-06-20 18:00:00, parameter=Parameter(parameterName=10, parameterUnit=百分比, parameterValue=null), startTime=2022-06-20 12:00:00), Time(endTime=2022-06-21 06:00:00, parameter=Parameter(parameterName=10, parameterUnit=百分比, parameterValue=null), startTime=2022-06-20 18:00:00), Time(endTime=2022-06-21 18:00:00, parameter=Parameter(parameterName=10, parameterUnit=百分比, parameterValue=null), startTime=2022-06-21 06:00:00)]), WeatherElement(elementName=MinT, time=[Time(endTime=2022-06-20 18:00:00, parameter=Parameter(parameterName=27, parameterUnit=C, parameterValue=null), startTime=2022-06-20 12:00:00), Time(endTime=2022-06-21 06:00:00, parameter=Parameter(parameterName=26, parameterUnit=C, parameterValue=null), startTime=2022-06-20 18:00:00), Time(endTime=2022-06-21 18:00:00, parameter=Parameter(parameterName=26, parameterUnit=C, parameterValue=null), startTime=2022-06-21 06:00:00)]), WeatherElement(elementName=CI, time=[Time(endTime=2022-06-20 18:00:00, parameter=Parameter(parameterName=悶熱, parameterUnit=null, parameterValue=null), startTime=2022-06-20 12:00:00), Time(endTime=2022-06-21 06:00:00, parameter=Parameter(parameterName=舒適至悶熱, parameterUnit=null, parameterValue=null), startTime=2022-06-20 18:00:00), Time(endTime=2022-06-21 18:00:00, parameter=Parameter(parameterName=舒適至悶熱, parameterUnit=null, parameterValue=null), startTime=2022-06-21 06:00:00)]), WeatherElement(elementName=MaxT, time=[Time(endTime=2022-06-20 18:00:00, parameter=Parameter(parameterName=30, parameterUnit=C, parameterValue=null), startTime=2022-06-20 12:00:00), Time(endTime=2022-06-21 06:00:00, parameter=Parameter(parameterName=27, parameterUnit=C, parameterValue=null), startTime=2022-06-20 18:00:00), Time(endTime=2022-06-21 18:00:00, parameter=Parameter(parameterName=29, parameterUnit=C, parameterValue=null), startTime=2022-06-21 06:00:00)])])

----------

結論:

Retrofit 就是讓大家用較簡單的方法,可以把以前要轉換個半死的json 與取得API資料之步驟給大大簡化的工具.

所以以後我不用在辛苦的寫一大堆code...用這就對了!




然後問題來了,

Retrofit 可以做到擷取api資料,並可直接顯示到UI.

我們自己不用寫跟Http connection相關的程式碼就可以達成, 這就是Retrofit簡單的地方, 只需要定義一個Java interface, 跟幾個簡單的annotation即可

-----

那這樣何須RxJava or RxAndroid???

這個問題留給大家思考了.

OS: RxJava的優勢.最概括的兩個字:簡潔。而且當業務越繁瑣越複雜時這一點就越顯出優勢~它能夠保持簡潔。

那幹嘛不直接new Handler().postDelayed()?  Answer: 如果你的程序線程裡面做的操作很簡單,那麼你用new Handler().postDelayed()無所謂,但是如果你的操作很複雜,那麼這時候就體現出了RxJava的好處了.


留言

這個網誌中的熱門文章

最爛的銀行服務-玉山銀行

SMR疊瓦式hdd致命缺陷被解決????!!!

更改google drive預設存放目錄位置Change Google Drive Default Folder Location in Windows

ios app 上架時app icon要注意事項

Mark App Design Apps - Terms and Privacy Policy (服務條款,隱私權政策)

Gmail 永久刪除大型電子郵件

app bundle and bundletool. 關於aab安裝問題

關於google play console app應用程式簽署

舊有app在Android 12 閃退問題& app Splash screens

來談談admob廣告政策違規的不好體驗