跳至主要內容

请求参数注解(五)

guodongAndroid大约 5 分钟

前言

在前几篇文章中我们学习了 Retrofit 中大部分的注解,本篇文章我们学习下剩余的注解。

annotation-type

从上图可以看出剩余的注解还有:

  • @Query
  • @QueryMap
  • @QueryName
  • @Body
  • @SkipCallbackExecutor

其中 @SkipCallbackExecutor 注解由于笔者的学习疏忽没有在前几篇文章中注明,它属于标记注解一类,本文我们一起学习下。

Query

HTTP URL 中的查询参数是可选的,它可以是:nullemptynon-empty。对于大多数的 HTTP URLs 来说它是 Key-Value 参数形式的集合。

Key-Value 的参数形式中:

  1. value 是可选的,即可以没有值,
  2. key 是可重复的,即可以存在多个相同的键,

@Query

@Query 注解标记HTTP接口方法中的一个参数,表示这个参数是 URL 中的查询参数。参数值会经过 Retrofit#stringConverter(Type, Annotation[]) 转换,如果没有找到匹配的字符串转换器则使用 Object#toString(),最后再经过 URL 编码。

@Query 注解有两个参数,分别为:

  1. value:必选参数,表示查询参数中的键,
  2. 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 注解使用时有以下几点需要注意:

  1. 如果参数值是 null,则会被忽略,
  2. 如果标记的参数是集合或数组类型,集合或数组中为 null 元素会被忽略,
    1. 如果标记的参数是集合类型,那么必须是参数化类型,不能是原始类型,否则抛出异常,
  3. 如果参数值经过 Converter 转换后为 null,也会被忽略,

@QueryMap

@QueryMap 注解标记HTTP接口方法中的一个参数,这个参数必须是 Map 类型,表示这个参数包含零个或多个 URL 中的查询参数。参数 Map 的键值会经过 Retrofit#stringConverter(Type, Annotation[]) 转换,如果没有找到匹配的字符串转换器则使用 Object#toString(),最后再经过 URL 编码。

@QueryMap 注解目前有一个参数:

  1. 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 注解使用时有以下几点需要注意:

  1. 标记的参数值不能为 null,否则抛出异常,
  2. 标记的参数必须是 Map 类型且不能是 Map 的原始类型,否则抛出异常,
  3. Map 中的 Key 必须是 String 类型,否则抛出异常,
  4. Map 中的 Key 的值不能为 null,否则抛出异常,
  5. Map 中的 Value 的值不能为 null,否则抛出异常,
  6. Map 中的 Value 的值经过 Converter 转换后不能为 null,否则抛出异常,

@QueryName

@QueryName 注解标记HTTP接口方法中的一个参数,表示这个参数是 URL 中的查询参数,但是没有值。参数值会经过 Retrofit#stringConverter(Type, Annotation[]) 转换,如果没有找到匹配的字符串转换器则使用 Object#toString(),最后再经过 URL 编码。

@QueryName 注解目前只有一个参数:

  1. 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 注解使用时有以下几点需要注意:

  1. @QueryName 注解标记的参数可以是集合类型、数组类型以及其他类型,
  2. 参数如果是集合类型,不能直接使用原始类型,否则抛出异常,
  3. 参数值为 null 的话,会被忽略,
  4. 经过 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 注解使用时有以下几点需要注意:

  1. @Body 注解不能与 @FormUrlEncoded@Multipart 注解同时使用,否则抛出异常,
  2. @Body 注解不能存在于没有请求体的请求方法中,如:GET 请求,否则抛出异常,
  3. @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~