请求参数注解(五)
前言
在前几篇文章中我们学习了 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~