Retrofit 使用教學
markdown
## Retrofit簡介
Retrofit 是一個網路連結套件,可以在連結網路的時候做好封裝的效果,可以跟 OkHttp 以及 RxJava 合併使用
## Retrofit應用
使用到的三方套件:
``` Java
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
implementation 'com.squareup.okhttp3:okhttp:3.11.0'
```
首先要先產生出Retrofit的實體物件:
```Kotlin
class RetrofitServiceGenerator private constructor() {
private val retrofit: Retrofit
private val okHttpClient = OkHttpClient()
init {
retrofit = Retrofit.Builder()
.baseUrl(Config.URL)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build()
}
companion object {
private val manager = AppClientManager()
val client: Retrofit
get() = manager.retrofit
}
}
```
上述可看到兩行程式碼:
```Kotlin
.addConverterFactory(GsonConverterFactory.create())
```
這邊是使用Google出的Json處理工具來進行轉換(Gson)
```Kotlin
.client(okHttpClient)
```
另外可以看到.client這邊目前是使用預設的okHttpClient,Retrofit本身底層是使用OkHttp的Client,若有一些特殊情境(ex. 網路回傳錯誤代碼)可以寫自己的攔截器或是調整設定
實體物件建立完後,再來示範串接一個RESTFUL API
隨便拿一個網路上提供的GET網址如下
```Kotlin
https://jsonplaceholder.typicode.com/posts
```
回傳資料格式如下:
```Kotlin
[
{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
},
{
"userId": 1,
"id": 2,
"title": "qui est esse",
"body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"
},
//...
]
```
範例回傳的格式是由四個欄位組成,因此我們可以將Response 宣告成以下類別:
```Kotlin
class GetSampleElementResponse {
@SerializedName("userId")
var userId: Int = 0
@SerializedName("id")
var id: Int = 0
@SerializedName("title")
var title: String? = null
@SerializedName("body")
var body: String? = null
}
```
此時也宣告一個interface透過retrofit使用這個response class,API回來的資訊為非同部,因此使用Call的方式來處理,retrofit 會對這個行為進行非同步處理,如下:
```Kotlin
interface ApiService {
@GET("/posts")
fun getSampleElement(): Call
- >
}
```
設定完成後就可以開始使用Retrofit,宣告一個按鈕並寫其觸發事件:
```Kotlin
test.setOnClickListener {
val apiService = RetrofitServiceGenerator.client.create(ApiService::class.java)
apiService.index().enqueue(object : Callback
- > {
override fun onResponse(call: Call
- >, response: Response
- >) {
val sb = StringBuffer()
val list = response.body()
for (p in list!!) {
sb.append(p.body)
sb.append("\n")
sb.append("---------------------\n")
}
tv.text = sb.toString()
}
override fun onFailure(call: Call
- >, t: Throwable) {
}
})
}
```
當我們把資料抓取回來就可以透過Response物件取出我們的Json,Retrofit會自動幫我們把對應的Json轉成對應的物件GetSampleElementResponse,根據一開始interface定義好的方式轉成List,這樣就可以直接使用List。
## Retrofit 延伸功能
### APIService 其他使用方式
在範例中我們是使用一個簡單的Get方法,在APIService中還有許多使用方式
網址後面可以直接帶入相對應的變數:
```Kotlin
@GET("api/user/detail/{listid}")
fun getSampleElement(@Path("listid")id: String): Call
- >
```
若你的參數是裝在Body裡面,可以這樣使用
```Kotlin
@GET("api/user/detail/{listid}")
fun getSampleElement(@Path("listid")id: String , @Body requestBody: GetSampleRequestBody): Call
- >
```
若帶入的參數很多時,可以使用QueryMap包起來
```Kotlin
@GET("api/user/detail/{listid}")
fun getSampleElement(@Path("listid")id: String , @QueryMap map: Map
- >
```
### OkHttp提供攔截器功能
特殊情境Sample:Server端若回傳307(或是其它需特殊處理的Error Code)錯誤後我們要自己手動轉location所導的網址,可能就需要自己寫一個攔截器,去做重新轉址的動作
```Java
OkHttpClient client = new OkHttpClient.Builder()
.followRedirects(false); //禁止OkHttp的重新轉址動作
.addInterceptor(new RedirectInterceptor()) //我們自己的攔截器
.build();
```
```Java
public class RedirectInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
okhttp3.Request request = chain.request();
Response response = chain.proceed(request);
int code = response.code();
if (code == 307) {
//拿要轉的網址
String location = response.headers().get("Location");
LogUtils.e("重新導的網址:", "location = " + location);
Request newRequest = request.newBuilder().url(location).build();
response = chain.proceed(newRequest);
}
return response;
}
}
```
留言
張貼留言