Retrofit各個注解的含義及作用

寫在前面

本篇文章基于retrofit-2.1進行分析.

1. 各個注解的含義及使用

1.1 Body注解:

作用于方法的參數(shù)

使用該注解定義的參數(shù)不可為null

當(dāng)你發(fā)送一個post或put請求,但是又不想作為請求參數(shù)或表單的方式發(fā)送請求時,使用該注解定義的參數(shù)可以直接傳入一個實體類,retrofit會通過convert把該實體序列化并將序列化后的結(jié)果直接作為請求體發(fā)送出去.

示例:

//實體class Repo {finalString owner;finalString name;? ? Repo(String owner, String name) {this.owner = owner;this.name = name;? ? }? }//接口interface Service {@POST("/")? ? Call sendNormal(@BodyRepo repo);

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

1.2 DELETE注解:

用于發(fā)送一個DELETE請求

DELETE注解一般必須添加相對路徑或絕對路徑或者全路徑,如果不想在DELETE注解后添加請求路徑,則可以在方法的第一個參數(shù)中用@Url注解添加請求路徑

1.3 Field注解:

作用于方法的參數(shù)

用于發(fā)送一個表單請求

用String.valueOf()把參數(shù)值轉(zhuǎn)換為String,然后進行URL編碼,當(dāng)參數(shù)值為null值時,會自動忽略,如果傳入的是一個List或array,則為每一個非空的item拼接一個鍵值對,每一個鍵值對中的鍵是相同的,值就是非空item的值,如: name=張三&name=李四&name=王五,另外,如果item的值有空格,在拼接時會自動忽略,例如某個item的值為:張 三,則拼接后為name=張三.

示例:

//普通參數(shù)@FormUrlEncoded@POST("/")Call example(@Field("name") String name,@Field("occupation") String occupation);//固定或可變數(shù)組@FormUrlEncoded@POST("/list")? Call example(@Field("name") String... names);

1

2

3

4

5

6

7

8

9

1

2

3

4

5

6

7

8

9

1.4 FieldMap注解:

作用于方法的參數(shù)

用于發(fā)送一個表單請求

map中每一項的鍵和值都不能為空,否則拋出IllegalArgumentException異常

示例:

@FormUrlEncoded@POST("/things")? Call things(@FieldMapMap fields);

1

2

3

1

2

3

1.5 FormUrlEncoded注解:

用于修飾Field注解和FieldMap注解

使用該注解,表示請求正文將使用表單網(wǎng)址編碼。字段應(yīng)該聲明為參數(shù),并用@Field注釋或FieldMap注釋。使用FormUrlEncoded注解的請求將具”application / x-www-form-urlencoded” MIME類型。字段名稱和值將先進行UTF-8進行編碼,再根據(jù)RFC-3986進行URI編碼.

1.6 GET注解

用于發(fā)送一個get請求

GET注解一般必須添加相對路徑或絕對路徑或者全路徑,如果不想在GET注解后添加請求路徑,則可以在方法的第一個參數(shù)中用@Url注解添加請求路徑

1.7 HEAD注解

用于發(fā)送一個HEAD請求

HEAD注解一般必須添加相對路徑或絕對路徑或者全路徑,如果不想在HEAD注解后添加請求路徑,則可以在方法的第一個參數(shù)中用@Url注解添加請求路徑

1.8 Header注解:

作用于方法的參數(shù),用于添加請求頭

使用該注解定義的請求頭可以為空,當(dāng)為空時,會自動忽略,當(dāng)傳入一個List或array時,為拼接每個非空的item的值到請求頭中.

具有相同名稱的請求頭不會相互覆蓋,而是會照樣添加到請求頭中

示例:

@GET("/")? Call foo(@Header("Accept-Language") String lang);

1

2

1

2

1.9 HeaderMap注解:

作用于方法的參數(shù),用于添加請求頭

以map的方式添加多個請求頭,map中的key為請求頭的名稱,value為請求頭的值,且value使用String.valueOf()統(tǒng)一轉(zhuǎn)換為String類型,

map中每一項的鍵和值都不能為空,否則拋出IllegalArgumentException異常

示例:

@GET("/search")voidlist(@HeaderMapMap headers);//mapMap headers =newHashMap()<>;? headers.put("Accept","text/plain");? headers.put("Accept-Charset","utf-8");

1

2

3

4

5

6

7

1

2

3

4

5

6

7

2.0 Headers注解:

作用于方法,用于添加一個或多個請求頭

具有相同名稱的請求頭不會相互覆蓋,而是會照樣添加到請求頭中

示例:

//添加一個請求頭@Headers("Cache-Control: max-age=640000")@GET("/") ...//添加多個請求頭@Headers({"X-Foo: Bar","X-Ping: Pong"})@GET("/")? ...

1

2

3

4

5

6

7

8

9

10

1

2

3

4

5

6

7

8

9

10

2.1 HTTP注解:

作用于方法,用于發(fā)送一個自定義的HTTP請求

示例:

//自定義HTTP請求的標(biāo)準(zhǔn)樣式interface Service {@HTTP(method ="CUSTOM", path ="custom/endpoint/")? ? Call customEndpoint();? }//發(fā)送一個DELETE請求interface Service {@HTTP(method ="DELETE", path ="remove/", hasBody =true)? ? Call deleteObject(@BodyRequestBody object);? }

1

2

3

4

5

6

7

8

9

10

1

2

3

4

5

6

7

8

9

10

2.2 Multipart注解:

作用于方法

使用該注解,表示請求體是多部分的。 每一部分作為一個參數(shù),且用Part注解聲明

2.3 Part注解:

作用于方法的參數(shù),用于定義Multipart請求的每個part

使用該注解定義的參數(shù),參數(shù)值可以為空,為空時,則忽略

使用該注解定義的參數(shù)類型有以下3種方式可選:

1,如果類型是okhttp3.MultipartBody.Part,內(nèi)容將被直接使用。 省略part中的名稱,即 @Part MultipartBody.Part part

2,如果類型是RequestBody,那么該值將直接與其內(nèi)容類型一起使用。 在注釋中提供part名稱(例如,@Part(“foo”)RequestBody foo)。

3,其他對象類型將通過使用轉(zhuǎn)換器轉(zhuǎn)換為適當(dāng)?shù)母袷健?在注釋中提供part名稱(例如,@Part(“foo”)Image photo)。

示例:

@Multipart@POST("/")Call example(@Part("description") String description,@Part(value ="image", encoding ="8-bit") RequestBody image);

1

2

3

4

5

1

2

3

4

5

2.4 PartMap注解:

作用于方法的參數(shù),以map的方式定義Multipart請求的每個part

map中每一項的鍵和值都不能為空,否則拋出IllegalArgumentException異常

使用該注解定義的參數(shù)類型有以下2種方式可選:

1,如果類型是RequestBody,那么該值將直接與其內(nèi)容類型一起使用。

2,其他對象類型將通過使用轉(zhuǎn)換器轉(zhuǎn)換為適當(dāng)?shù)母袷健?/p>

示例:

@Multipart@POST("/upload")Call upload(@Part("file") RequestBody file,@PartMapMap params);

1

2

3

4

5

1

2

3

4

5

2.5 OPTIONS注解:

用于發(fā)送一個OPTIONS請求

OPTIONS注解一般必須添加相對路徑或絕對路徑或者全路徑,如果不想在OPTIONS注解后添加請求路徑,則可以在方法的第一個參數(shù)中用@Url注解添加請求路徑

2.6 PATCH注解:

用于發(fā)送一個PATCH請求

PATCH注解一般必須添加相對路徑或絕對路徑或者全路徑,如果不想在PATCH注解后添加請求路徑,則可以在方法的第一個參數(shù)中用@Url注解添加請求路徑

2.7 Path注解:

作用于方法的參數(shù)

在URL路徑段中替換指定的參數(shù)值。使用String.valueOf()和URL編碼將值轉(zhuǎn)換為字符串。

使用該注解定義的參數(shù)的值不可為空

參數(shù)值默認(rèn)使用URL編碼

示例:

//標(biāo)準(zhǔn)使用方式,默認(rèn)使用URL編碼@GET("/image/{id}")Call example(@Path("id")intid);//默認(rèn)使用URL編碼@GET("/user/{name}")Call encoded(@Path("name") String name);//不使用URL編碼@GET("/user/{name}")Call notEncoded(@Path(value="name", encoded=true) String name);

1

2

3

4

5

6

7

8

9

1

2

3

4

5

6

7

8

9

2.8 POST注解:

用于發(fā)送一個POST請求

POST注解一般必須添加相對路徑或絕對路徑或者全路徑,如果不想在POST注解后添加請求路徑,則可以在方法的第一個參數(shù)中用@Url注解添加請求路徑

2.9 PUT注解:

用于發(fā)送一個PUT請求

PUT注解一般必須添加相對路徑或絕對路徑或者全路徑,如果不想在PUT注解后添加請求路徑,則可以在方法的第一個參數(shù)中用@Url注解添加請求路徑

3.0 Query注解:

作用于方法的參數(shù)

用于添加查詢參數(shù),即請求參數(shù)

參數(shù)值通過String.valueOf()轉(zhuǎn)換為String并進行URL編碼

使用該注解定義的參數(shù),參數(shù)值可以為空,為空時,忽略該值,當(dāng)傳入一個List或array時,為每個非空item拼接請求鍵值對,所有的鍵是統(tǒng)一的,如: name=張三&name=李四&name=王五.

示例:

@GET("/list")Call list(@Query("page")intpage);@GET("/list")Call list(@Query("category") String category);//傳入一個數(shù)組@GET("/list")Call list(@Query("category") String... categories);//不進行URL編碼@GET("/search")Call list(@Query(value="foo", encoded=true) String foo);

1

2

3

4

5

6

7

8

9

10

1

2

3

4

5

6

7

8

9

10

3.1 QueryMap注解:

作用于方法的參數(shù)

以map的形式添加查詢參數(shù),即請求參數(shù)

參數(shù)的鍵和值都通過String.valueOf()轉(zhuǎn)換為String格式

map的鍵和值默認(rèn)進行URL編碼

map中每一項的鍵和值都不能為空,否則拋出IllegalArgumentException異常

示例:

//使用默認(rèn)URL編碼@GET("/search")Call list(@QueryMapMap filters);//不使用默認(rèn)URL編碼@GET("/search")Call list(@QueryMap(encoded=true) Map filters);

1

2

3

4

5

6

1

2

3

4

5

6

3.2 Streaming注解:

作用于方法

處理返回Response的方法的響應(yīng)體,即沒有將body()轉(zhuǎn)換為byte []。

3.3 Url注解:

作用于方法參數(shù)

用于添加請求的接口地址

示例:

@GETCall list(@UrlString url);

1

2

1

2

注意事項:

1,以上部分注解真正的實現(xiàn)在ParameterHandler類中,,每個注解的真正實現(xiàn)都是ParameterHandler類中的一個final類型的內(nèi)部類,每個內(nèi)部類都對各個注解的使用要求做了限制,比如參數(shù)是否可空,鍵和值是否可空等.

2,FormUrlEncoded注解和Multipart注解不能同時使用,否則會拋出methodError(“Only one encoding annotation is allowed.”);可在ServiceMethod類中parseMethodAnnotation()方法中找到不能同時使用的具體原因.

3,Path注解與Url注解不能同時使用,否則會拋出parameterError(p, “@Path parameters may not be used with @Url.”),可在ServiceMethod類中parseParameterAnnotation()方法中找到不能同時使用的具體代碼.其實原因也很好理解: Path注解用于替換url路徑中的參數(shù),這就要求在使用path注解時,必須已經(jīng)存在請求路徑,不然沒法替換路徑中指定的參數(shù)啊,而Url注解是在參數(shù)中指定的請求路徑的,這個時候指定請求路徑已經(jīng)晚了,path注解找不到請求路徑,更別提更換請求路徑中的參數(shù)了.

4,對于FiledMap,HeaderMap,PartMap,QueryMap這四種作用于方法的注解,其參數(shù)類型必須為Map的實例,且key的類型必須為String類型,否則拋出異常(以PartMap注解為例):parameterError(p, “@PartMap keys must be of type String: ” + keyType);

5,使用Body注解的參數(shù)不能使用form 或multi-part編碼,即如果為方法使用了FormUrlEncoded或Multipart注解,則方法的參數(shù)中不能使用Body注解,否則拋出異常parameterError(p, “@Body parameters cannot be used with form or multi-part encoding.”);

小結(jié):

早就想把Retrofit的各個注解的含義和使用條件研究一番,但是幾個月來一直加班,根本沒多少時間仔細(xì)研讀,中間有點閑暇時間也想偷個懶休息一下,眼看著已經(jīng)是2016年最后一天了,再不研究就要等明年了,所以下定決心,花了大半天的時間,把Retrofit 2.1版本的源碼徹底的讀了一篇,邊讀變做筆記,讀完之后把這些筆記又做了一些整理,才有了這2016年最后一篇博客.當(dāng)然,文章中難免有錯誤或者不足之處,如果發(fā)現(xiàn),還請及時告知,謝謝啦~~

讀完源碼,發(fā)現(xiàn)Retrofit并不像理想中的那么好,這里說的不好不是說代碼架構(gòu)不好,而是單指易用性這個方面,所有會用Retrofit的朋友,都知道如何使用Retrofit發(fā)送一個請求:

需要寫至少一個接口

然后定義至少一個接口方法

然后構(gòu)建Retrofit

然后調(diào)用create方法生成接口類

然后調(diào)用enqueue或者 execute方法發(fā)送一個異步或同步請求

一個簡單的請求一共經(jīng)歷了5步,這還不算完:

- 你需要添加json解析器,如GsonConvertFactory,來自動序列化json串

- 你需要配置統(tǒng)一的cookie攔截器,這些代碼需要你自己編寫(網(wǎng)上復(fù)制粘貼的除外)

- 一般你還需要添加日志攔截器,因為在debug的時候你會發(fā)現(xiàn),Retrofit竟然他媽的不能拼接出完整的url請求地址(完整的請求地址包括請求的主機地址,接口名,所有請求參數(shù)拼接,Retrofit最多只能看到接口,后面拼接的參數(shù)是看不到的,這在調(diào)試的時候很讓人不爽)

如果你說這些都不是事,那么我們再看:

Retrofit提供了MultiPart注解,說明我們可以上傳文件,又提供了Streaming注解,說明我們可以下載文件,我們知道Retrofit可以干這些事,但是我們還是沒有辦法直接寫上傳下載代碼,這些東西都需要我們自己去封裝,這也是為什么目前有很多基于Retrofit構(gòu)建的二次封裝庫的原因

很多人用Retrofit基本上也就會發(fā)送一個get或者post請求,也就熟悉個別幾個作用于參數(shù)的注解,如果你讓這些人用Retrofit去搞定所有RESTful風(fēng)格的接口,可能大部分人直接懵逼,因為他們不知道各個方法的注解和參數(shù)的注解怎么搭配使用才能完美運行,而不是拋出異常,因為Retrofit制定的這些規(guī)則你必須遵守

有些狂熱的Retrofit粉絲大呼Retrofit有著插拔式設(shè)計,想用就用,想不用就不用,耦合很低,這確實是Retrofit的優(yōu)點,但也正是因為足夠靈活,導(dǎo)致易用性不夠,不然也不會產(chǎn)生這么多基于Retrofit構(gòu)建的框架了

算了,不噴了.畢竟一會就到2017年了,給2016年留下個好印象把,作為程序員,對新技術(shù)新東西保持強烈的好奇心的同時還應(yīng)該保持一個清醒的頭腦,不要盲目跟風(fēng).我去,說好不噴了,怎么又噴上了.

哎,看掘金上其他開發(fā)者發(fā)表的博客,都是對2016年一年的總結(jié)及2017年的展望,我2016年的最后一篇博客竟然是一篇純純的技術(shù)文章,無所謂啦,每個人的境遇不一樣,誰讓我的新年簽是:簡單,比2016過得好就行!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 本篇文章基于retrofit-2.1進行分析. 方法注解:@GET、@POST、@PUT、@DELETE、@PAT...
    丨Fan閱讀 7,931評論 0 11
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,993評論 19 139
  • 整體Retrofit內(nèi)容如下: 1、Retrofit解析1之前哨站——理解RESTful2、Retrofit解析2...
    隔壁老李頭閱讀 15,163評論 4 39
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,560評論 25 708
  • 她說。 阿姨,你真漂亮。 她說。 阿姨,你的眼睛是藍(lán)色的,真漂亮。 …… 擁擠的公交車上,人們蹙著眉摩肩接踵。車門...
    藍(lán)莫熙閱讀 272評論 0 1