众所周知,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
/** * 知识体系下的文章 * https://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<ArticleListResponse>对于这里是去查询知识体系下的文章,其中@Path注解会把路径中的{page}替换成page参数实际的值,也就是分页数,这样就可以去实现分页效果
-
@Url
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
下面可以看下示例:
@GET("/list/json")
fun getList(@Query("page") page: Int): Call<ResponseBody>
动态指定查询条件组: @QueryMap
用于以map的形式添加查询参数,即请求参数,参数的键值对都是通过String.valueof()转换为String格式,其中它的键和值都是默认进行URL编码,map中每一项的键和值都不能为空,否则抛出IllegalArgumentException异常
下面可以示例:
//不使用默认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请求数据类型,多用于以表单的形式上传数据
@POST("/register")
fun registerUser(@Field("id") userId: String): Call<ResponseBody>
@FieldMap和@Field的作用基本一样的,不同的是它用于不确定参数个数的情况下
传输数据类型JSON字符串:@Body
对于@Body,使用该注解定义的参数不可为nul,用POST方式将JSON字符串作为请求体发送到服务器中,简单来说,就是直接传入一个实体类,retrofit会通过convert把该实体序列化并将序列化后的结果直接作为请求体发送出去;
@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注解来标示起来,其他的都和单文件上传都一样,这里就不赘述了
@Multipart
@POST("user/photo")
fun updateUser(
@PartMap photo: Map<String, ResponseBody>,
@Part("description") description: ResponseBody
): Call<ResponseBody>
消息报头Header
在HTTP请求中,为了防止攻击或者过滤掉不安全的访问,或者需要添加加密等等,保证请求的安全,这时候通常都会在消息报头中携带一些特殊的消息头处理,所以Retrofit提供了@Header来添加消息报头,一般有两种方式,静态和动态
-
静态实现方式
@GET("some/endpoint") @Headers("Accept-Encoding: application/json") fun getType():Call<ResponseBody>如果想要添加多个报头,可以使用{}包含起来,@Headers注解代码已经是一个String的数组,所以可以添加多个
@Headers( "Accept-Encoding: application/json", "User-Agent:MoonRetrofit") fun getCarType():Call<ResponseBody> -
动态实现方式
@GET("some/endpoint") fun getCarType2(@Header("Location") location: String) : Call<ResponseBody>使用@Header注解,可以调用getCarType2接口来动态地添加消息头部,以上就是消息头部注解的简单使用
-
关于@Header和Headers
话不多说,直接上源码,可以直观看到@Header和@Headers之间的区别(Headers是String数组所以适用于多个请求头的时候,而Header是动态添加的时候)
@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进阶之光》
未完待续