【一起學習Android開源框架】Retrofit註解解析(第三部分)
highlight: a11y-light theme: vue-pro
眾所周知,Retrofit底層是基於Okhttp實現的,與別網路框架不同,它更多的是使用執行時註解的方式提供相應的功能,在請求網路的時候更加便捷,下面我們就來簡單解析下Retrofit常用的一些註解
Retrofit的註解分類
相對於其他網路請求框架來說,最大的不同就是Retrofit使用了註解。 它的註解主要分為三大類
- Http請求方法註解
- 包含GET,POST,PUT,DELETE,HEAD,PATCH,OPTIONS 和HTTP
- 標記類註解
- 包含FromUrlEncoded,Multipart,Streaming
- 引數類註解
- 包含Header,Body,Path,Field,FieldMap,Part,PartMap,Query和QueryMap
關於Http請求方法註解,HTTP可以替換掉之前的七種方法,也可以使用擴充套件請求方法; 關於標記類註解,其中Streaming代表響應的資料以流的形式返回, 不使用它的時候預設會把全部資料載入到記憶體,所以下載大檔案的時候需要載入這個註解;
下面我會簡單介紹幾種常用的註解的用法,不當當只有GET和POST請求,實際上這些註解請求方法各自有各自的使用場景
GET請求訪問網路
首先我們用一個GET請求來請求網路,具體使用可以看官網例子或者前面的第一部分,這裡就不贅述了。使用Retrofit提供的@Get註解,顧名思義它代表的是GET請求;
一般GET請求,必須新增相對路徑或絕對路徑或者全路徑,如果不想在GET註解後新增請求路徑,則可以在方法的第一個引數中用@Url註解新增請求路徑,這個後面會說到
動態配置URL地址:@Path,@Url
兩個註解都是動態配置URL地址,對於@Path在GET註解中包含了{path},它對應著@Path註解中的”path“,用來替換{path},也就是我們傳入的String值;對於@Url註解表示動態url請求資料,下面舉個例子
- @Path
```kotlin
/**
- 知識體系下的文章
- http://www.wanandroid.com/article/list/0/json?cid=168
- @param page page
- @param cid cid
*/
@GET("/article/list/{page}/json")
fun getTreeArticleList(
@Path("page") page: Int,
@Query("cid") cid: Int
): Observable
```
對於這裡是去查詢知識體系下的文章,其中@Path註解會把路徑中的{page}替換成page引數實際的值,也就是分頁數,這樣就可以去實現分頁效果
- @Url
kotlin
var retrofit = Retrofit.Builder()
.baseUrl("http://www.wanandroid.com/")
.build()
@GET
fun getData(@Url user: String): Call<List<UserData>>
ps: 注意的是使用@Path,path對應的路徑不能包含”/”,不然每個加到host Url後面的東西都會被省略掉
動態指定查詢條件:@Query
用於新增查詢引數,即請求引數,引數值是通過String.valueOf()轉換成String並且進行URL編碼,引數值通過String.valueOf()轉換為String並進行URL編碼
使用該註解定義的引數,引數值可以為空,為空時,忽略該值,當傳入一個List或array時,為每個非空item拼接請求鍵值對,所有的鍵是統一的,比如說page = 1& page = 2 & page = 3
下面可以看下示例:
kotlin
@GET("/list/json")
fun getList(@Query("page") page: Int): Call<ResponseBody>
動態指定查詢條件組: @QueryMap
用於以map的形式新增查詢引數,即請求引數,引數的鍵值對都是通過String.valueof()轉換為String格式,其中它的鍵和值都是預設進行URL編碼,map中每一項的鍵和值都不能為空,否則丟擲IllegalArgumentException異常
下面可以示例:
```kotlin
//不使用預設URL編碼
@GET("/search")
fun listOne(@QueryMap filters: Map<String?, String>): Call<ResponseBody>
//使用預設URL編碼
@GET("/search")
fun listTwo(@QueryMap(encoded = true) filters: Map<String?, String?>?): Call<ResponseBody>
```
POST請求網路
簡單來說,@Post註解用於傳送一個post請求,一般必須新增相對路徑或絕對路徑或者全路徑,如果不想在POST註解後新增請求路徑,則可以在方法的第一個引數中用@Url註解新增請求路徑
傳輸資料型別為鍵值對:@Field
當我們傳輸資料型別為鍵值對的時候,這也是我們最常用的POST請求資料型別,多用於以表單的形式上傳資料
kotlin
@POST("/register")
fun registerUser(@Field("id") userId: String): Call<ResponseBody>
@FieldMap和@Field的作用基本一樣的,不同的是它用於不確定引數個數的情況下
傳輸資料型別JSON字串:@Body
對於@Body,使用該註解定義的引數不可為nul,用POST方式將JSON字串作為請求體傳送到伺服器中,簡單來說,就是直接傳入一個實體類,retrofit會通過convert把該實體序列化並將序列化後的結果直接作為請求體傳送出去;
kotlin
@POST("/login")
fun login(@Body user: User): Call<ResponseBody>
單個檔案上傳:@Part
話不多說,先舉個例子
```kotlin
@Multipart
@POST("user/photo")
fun updateUser(
@Part photo: MultipartBody.Part,
@Part("description") description: ResponseBody
): Call<ResponseBody>
```
MutiPart註解表示允許多個@Part,updateUser方法的第一個引數是準備上傳的圖片檔案,使用了MultipartBody.part型別;另一個引數是RequestBody型別,它用來傳遞簡單的鍵值對
多個檔案上傳:@PartMap
多個檔案上傳和單檔案上傳是相似的,只是使用了Map封裝了上傳的檔案,並用@PartMap註解來標示起來,其他的都和單檔案上傳都一樣,這裡就不贅述了
kotlin
@Multipart
@POST("user/photo")
fun updateUser(
@PartMap photo: Map<String, ResponseBody>,
@Part("description") description: ResponseBody
): Call<ResponseBody>
訊息報頭Header
在HTTP請求中,為了防止攻擊或者過濾掉不安全的訪問,或者需要新增加密等等,保證請求的安全,這時候通常都會在訊息報頭中攜帶一些特殊的訊息頭處理,所以Retrofit提供了@Header來新增訊息報頭,一般有兩種方式,靜態和動態
- 靜態實現方式
kotlin
@GET("some/endpoint")
@Headers("Accept-Encoding: application/json")
fun getType():Call<ResponseBody>
如果想要新增多個報頭,可以使用{}包含起來,@Headers註解程式碼已經是一個String的陣列,所以可以新增多個
kotlin
@Headers(
"Accept-Encoding: application/json",
"User-Agent:MoonRetrofit")
fun getCarType():Call<ResponseBody>
- 動態實現方式
kotlin
@GET("some/endpoint")
fun getCarType2(@Header("Location") location: String) : Call<ResponseBody>
使用@Header註解,可以呼叫getCarType2介面來動態地新增訊息頭部,以上就是訊息頭部註解的簡單使用
- 關於@Header和Headers
話不多說,直接上原始碼,可以直觀看到@Header和@Headers之間的區別(Headers是String陣列所以適用於多個請求頭的時候,而Header是動態新增的時候)
```java @Documented @Retention(RUNTIME) @Target(PARAMETER) public @interface Header { String value(); }
@Documented @Target(METHOD) @Retention(RUNTIME) public @interface Headers { String[] value(); } ```
額外說的話
- 比較深入學習Retrofit後,會發現它的在一些易用性方面的問題,除了它是基於OKhTTP框架上封裝實現網路請求,除了基本的網路請求步驟,需要新增json解析器,GsonConvertFactory,來自動序列化json串,需要配置統一的cookie攔截器,這些程式碼需要你自己編寫,會比較麻煩
- 對於Retrofit提供的這些註解,就是方面我們能更便捷的實現某些功能,但是這些東西還是需要自己去封裝,比如說上傳下載,有MulitPart和Streaming,但是我們是沒有辦法直接寫上傳下載的
- 相信很多人使用Retrofit基本就是Get和post請求,我也是,對於各個方法的註解和引數的註解搭配還是比較懵逼的,而且我們還得遵守Retrofit的規則,否則就會出現各種各樣的問題
結語
- 以上就是Retrofit中一些常用註解的使用解析,到這裡我們已經學會了如何使用Retrofit,包括它的簡單使用,常用的註解解析,以及它的使用代理模式,為接下來正式學習分析Retrofit原始碼做好鋪墊
- 關於Retrofit更詳細的註解使用以及原理,上面還有很多註解沒有說明,大家可以去Retrofit官方網站以及網路其他資源學習
- 參考資料:《Android進階之光》
未完待續
- 請收下這些Kotlin開發必知必會的編碼實踐方式
- 日常思考,目前Kotlin協程能完全取代Rxjava嗎
- 誇誇其談,簡單說說HTTP的優化歷程
- 【一起學習開源框架】Retrofit相對於OKHttp,解決了什麼問題
- Kotlin Sequences Api:入門
- 【日常小問題】談談Rxjava中的操作符以及幾種常見的Subject,應用到實際場景中
- 【一起學習Android開源框架】Retrofit原始碼解析-1(第四部分)
- 【日常小問題】解決BottomSheetDialogFragment中多個fragment滑動衝突
- 【一起學習Android開源框架】Retrofit註解解析(第三部分)
- 【一起學習Android開源框架】Retrofit使用的代理模式解析(第二部分)
- 【一起學習Android開源框架】Retrofit的簡單使用(第一部分)