请求参数注解(五)
前言
在前几篇文章中我们学习了 Retrofit 中大部分的注解,本篇文章我们学习下剩余的注解。

从上图可以看出剩余的注解还有:
@Query@QueryMap@QueryName@Body@SkipCallbackExecutor
其中
@SkipCallbackExecutor注解由于笔者的学习疏忽没有在前几篇文章中注明,它属于标记注解一类,本文我们一起学习下。
Query
HTTP URL 中的查询参数是可选的,它可以是:null、empty 和 non-empty。对于大多数的 HTTP URLs 来说它是 Key-Value 参数形式的集合。
在 Key-Value 的参数形式中:
value是可选的,即可以没有值,key是可重复的,即可以存在多个相同的键,
@Query
@Query 注解标记HTTP接口方法中的一个参数,表示这个参数是 URL 中的查询参数。参数值会经过 Retrofit#stringConverter(Type, Annotation[]) 转换,如果没有找到匹配的字符串转换器则使用 Object#toString(),最后再经过 URL 编码。
@Query 注解有两个参数,分别为:
value:必选参数,表示查询参数中的键,encoded:可选参数,表示查询参数的Key-Value是否已经经过 URL 编码,为true的话,Retrofit 内部不会再经过 URL 编码,默认false,
简单使用示例如下:
interface Service {
@GET("foo/bar")
Call<ResponseBody> method(@Query("page") int page);
}
Service service = retrofit.create(Service.class);
service.method(1);
// /foo/bar?page=1
@Query 注解使用时有以下几点需要注意:
- 如果参数值是
null,则会被忽略, - 如果标记的参数是集合或数组类型,集合或数组中为
null元素会被忽略,- 如果标记的参数是集合类型,那么必须是参数化类型,不能是原始类型,否则抛出异常,
- 如果参数值经过
Converter转换后为null,也会被忽略,
@QueryMap
@QueryMap 注解标记HTTP接口方法中的一个参数,这个参数必须是 Map 类型,表示这个参数包含零个或多个 URL 中的查询参数。参数 Map 的键值会经过 Retrofit#stringConverter(Type, Annotation[]) 转换,如果没有找到匹配的字符串转换器则使用 Object#toString(),最后再经过 URL 编码。
@QueryMap 注解目前有一个参数:
encoded:可选参数,表示查询参数的Key-Value是否已经经过 URL 编码,为true的话,Retrofit 内部不会再经过 URL 编码,默认false,
简单使用示例:
interface Service {
@GET("foo/bar")
Call<ResponseBody> method(@QueryMap Map<String, String> keywords);
}
Service service = retrofit.create(Service.class);
service.method(ImmutableMap.of("name", "guodongAndroid", "age", "18");
// /foo/bar?name=guodongAndroid&age=18
@QueryMap 注解使用时有以下几点需要注意:
- 标记的参数值不能为
null,否则抛出异常, - 标记的参数必须是
Map类型且不能是Map的原始类型,否则抛出异常, Map中的Key必须是String类型,否则抛出异常,Map中的Key的值不能为null,否则抛出异常,Map中的Value的值不能为null,否则抛出异常,Map中的Value的值经过Converter转换后不能为null,否则抛出异常,
@QueryName
@QueryName 注解标记HTTP接口方法中的一个参数,表示这个参数是 URL 中的查询参数,但是没有值。参数值会经过 Retrofit#stringConverter(Type, Annotation[]) 转换,如果没有找到匹配的字符串转换器则使用 Object#toString(),最后再经过 URL 编码。
@QueryName 注解目前只有一个参数:
encoded:可选参数,表示查询参数的Key-Value是否已经经过 URL 编码,为true的话,Retrofit 内部不会再经过 URL 编码,默认false,
简单使用示例:
interface Service {
@GET("foo/bar")
Call<ResponseBody> method(@QueryName String keys);
}
Service service = retrofit.create(Service.class);
service.method("name(guodongAndroid)");
// /foo/bar?name(guodongAndroid)
@QueryName 注解使用时有以下几点需要注意:
@QueryName注解标记的参数可以是集合类型、数组类型以及其他类型,- 参数如果是集合类型,不能直接使用原始类型,否则抛出异常,
- 参数值为
null的话,会被忽略, - 经过
Converter转换后为null的话会抛出异常,
小结
| 注解 | 类型 | 适用场景 |
|---|---|---|
@Query | 动态 | 明确查询参数中的 Key,不明确 Value |
@QueryMap | 动态 | 1.Key-Value 都不明确2.一次传入多个查询参数 |
@QueryName | 动态 | 查询参数中只有 Key,没有 Value |
@QueryMap相对于@Query要更严格一些,在@Query注解下,被标记参数值为null的话会被忽略,而@QueryMap会抛出异常。
@Body
@Body 注解标记 HTTP 接口方法中的一个参数,表示这个参数是 HTTP 中的请求体。参数值会经过 Retrofit#requestBodyConverter(Type, Annotation[], Annotation[]) 转换,转换后的值将直接作为请求体。
@Body 注解目前没有参数。
简单使用示例:
interface Service {
@POST("foo/bar")
Call<ResponseBody> method(@Body String body);
}
Service service = retrofit.create(Service.class);
service.method("guodongAndroid");
@Body 注解使用时有以下几点需要注意:
@Body注解不能与@FormUrlEncoded和@Multipart注解同时使用,否则抛出异常,@Body注解不能存在于没有请求体的请求方法中,如:GET 请求,否则抛出异常,@Body注解标记的参数的值不能为null,否则抛出异常,
@SkipCallbackExecutor
@SkipCallbackExecutor 注解标记 HTTP 接口方法,表示当前 HTTP 接口方法不使用 Retrofit#callbackExecutor() 来回调 Callback#onResponse() 和 Callback#onFailure()。
简单使用示例:
interface Service {
@SkipCallbackExecutor
@GET("foo/bar")
Call<ResponseBody> method();
}
Service service = retrofit.create(Service.class);
service.method();
@SkipCallbackExecutor注解使用场景较少,目前仅做了解即可。
总结
呼~,Retrofit 注解相关的内容终于到完结的时候了。平时使用这些注解时感觉没有多少知识点,殊不知框架在背后默默做了多少检查与支持工作。
通过阅读 Retrofit 源码,发现但凡好的开源项目,代码都很精炼,注释也比代码多。
虽然注解相关的内容写了这么多,但基本都是现学现写,所以每个注解的特性和注意点我也记不住,那么就只能温故而知新了~
希望可以帮你更好的使用 Retrofit,happy~
