文章使用的Retrofit版本为:2.3.0
Retrofit已经问世很久了,现在再来讨论Retrofit的使用不免有些晚,但是也是为了巩固自己的知识,话不多说,直接开始:
Retrofit是什么?
其实Retrofit是对网络请求的一种封装,实际进行网络请求的并不是它本身,Retrofit内部依赖了okhttp与okio,就像我们在使用okhttp时进行封装一样,Retrofit通过一系列初始化配置之后,让我们可以通过注解的方式就能进行网络请求,很大程度上简化了我们在实际请求时所需要做的操作。
Retrofit怎么用?
- 添加依赖:
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
因为Retrofit已经内部依赖了okhttp,所以我们不需要额外再去添加依赖了。
- Retrofit初始化配置
object RetrofitCreate {
fun getApi(): Api {
return Retrofit.Builder()
.baseUrl("http://www.baidu.com/")
.client(OkHttpClient())
.build()
.create(Api::class.java)
}
}
我们从以上的几个方法开始看:
1、baseUrl()
,必需项,设置的是接口请求中的url基地址,必须以 /
结尾,否则会报错(原因我们在往后源码解析的文章中能知道),并且在调用A接口时如果注解中的地址已经包含了基地址,那么A接口每次调用时都以它自己的基地址覆盖设置的baseUrl,其他接口还是使用baseUrl。
2、client()
,可选项,设置的是OkhttpClient ,我们可以对OkHttpClient进行自定义,如果不配置的话Retrofit会使用默认的OkhttpClient。
3、cteate()
,必需项,指定我们将Retrofit的初始化与哪一个配置接口相结合。
- 添加请求配置的接口
这里以 GET 请求举例
interface Api {
@GET("hello/world")
fun getHelloWorld(@Query("name") name: String): Call<String>
}
@GET("hello/world")
这个方法上的注解就定义了这个接口的请求方式为 GET
、url为 hello/world
,这里的url会和第二步中Retrofit中的初始化配置协同工作,并且,如果你这里写的是完整路径,那么在Retrofit初始化时设置的baseUrl将在此次接口调用中无效,注意是 此次,并不会就此覆盖baseUrl。
@Query
这个参数的注解含义为参数名为字符串 name
,参数的值为调用时传入的值,方法的注解和参数的注解是搭配来使用的,这个我们稍后介绍。
Call<String>
为返回值,返回类型为 String,call 为Retrofit的包装类,能够调用同步、异步方法发起请求,实际发起请求的操作是转交到了Okhttp和okio去做。
发起异步的 GET
请求:
RetrofitCreate.getApi().getHelloWorld("jerry").enqueue(object:Callback<String>{
override fun onFailure(p0: Call<String>?, p1: Throwable?) {
}
override fun onResponse(p0: Call<String>?, p1: Response<String>?) {
}
})
结合图示代码的完整请求信息如下:
请求接口:http://www.baidu.com/hello/world?name=jerry
请求方法:GET
因为是 get 请求,参数已经拼接到了 url 上。
至此,一个简单的请求我们就完成了。当然,Retrofit 可不仅仅只有这点内容,Retrofit 的使用就是对其内部定义的各种注解的使用,所以我们就从注解开始。
Retrofit的注解
这就是所谓的开局一张图,剩下全靠吹:
- 方法注解
注解 | 作用 |
---|---|
@GET | 表明HTTP请求方法为GET,(可选)注解的value属性用来设置相对/绝对url |
@POST | 表明HTTP请求方法为POST,(可选)注解的value属性用来设置相对/绝对url |
@PUT | 表明HTTP请求方法为PUT,(可选)注解的value属性用来设置相对/绝对url |
@DELETE | 表明HTTP请求方法为DELETE ,(可选)注解的value属性用来设置相对/绝对url |
@HEAD | 表明HTTP请求方法为HEAD,(可选)注解的value属性用来设置相对/绝对url |
@PATCH | 表明HTTP请求方法为PATCH,(可选)注解的value属性用来设置相对/绝对url |
@OPTIONS | 表明HTTP请求方法为OPTIONS,(可选)注解的value属性用来设置相对/绝对url |
@HTTP | 通过@HTTP注解指定http协议的请求方法,是否允许body,(可选)注解的value属性用来设置相对/绝对url |
@Headers | 使用注解的value值数组作为HTTP的请求头,用于一些固定的Header参数 |
1.1. 标记类注解
注解 | 作用 |
---|---|
@FormUrlEncoded | 表明发起HTTP请求的RequestBody是form表单方式 |
@Multipart | 表明发起HTTP请求的RequestBody是Multipar方式 |
@Streaming | 用于直接返回流的函数 |
- 参数注解
注解 | 作用 |
---|---|
@Url | HTTP请求的url路径(相对/绝对),可以包含{path},如:http://xxx.com/{path1}/detail |
@Body | 表明此参数用作HTTP请求的body |
@Path | 用于动态替换URL路径中的 {path} |
@Field | 表明此参数用作HTTP请求的form表单参数,表单参数的key为注解的value值 |
@FieldMap | 以map形式传入的form表单参数 |
@Part | 表明参数为Http的multipart参数之一 |
@PartMap | 以map形式传入的multipart参数表 |
@Query | GET方法的query参数,用于拼接完整请求路径 |
@QueryMap | 以map传入的GET方法的query参数,用于拼接完整请求路径 |
@Header | 表明此参数用作HTTP请求的header,请求头的key为注解的value值 |
@HeaderMap | 以map形式传入的多个header键值对 |
直接用代码展示各个注解的使用方式:
interface Api {
//使用@Headers添加多个请求头
@Headers("User-Agent:android", "apikey:123456789")
@POST
fun post(@Url url: String, @QueryMap map: Map<String, String>): Call<Any>
@GET("hello/world")
operator fun get(@Header("token") token: String, @Query("id") activeId: Int): Call<Any>
@GET("hello/world")
fun ActiveList(): Call<Any>
@POST("hello/world")
fun post2(@QueryMap map: Map<String, String>): Call<Any>
/**
* 很多情况下,我们需要上传json格式的数据。比如当我们注册新用户的时候,因为用户注册时的数据相对较多,
* 并可能以后会变化,这时候,服务端可能要求我们上传json格式的数据。此时就要@Body注解来实现。
* 直接传入实体,它会自行转化成Json
*/
@POST("hello/{url}/world")
fun login(@Path("url") url: String, @Body post: Any): Call<Any>
/**
* 单张图片上传
* retrofit 2.0的上传和以前略有不同,需要借助@Multipart注解、@Part和MultipartBody实现。
*/
@Multipart
@POST("{url}")
fun upload(@Path("url") url: String, @Part file: MultipartBody.Part): Call<Any>
/**
* 多张图片上传
*/
@Multipart
@POST("hello/world")
fun upload(@PartMap map: Map<String, MultipartBody.Part>): Call<Any>
/**
* 图文混传
*/
@Multipart
@POST()
fun register(@Body post: Any, @PartMap map: Map<String, MultipartBody.Part>): Call<Any>
/**
* 文件下载
*/
@Streaming
@GET
fun downloadPicture(@Url fileUrl: String): Call<Any>
/**
* 这里需要注意的是如果下载的文件较大,比如在10m以上,那么强烈建议你使用@Streaming进行注解,否则将会出现IO异常.
*/
@Streaming
@GET
fun downloadPicture2(@Url fileUrl: String): Call<Any>
@POST
@FormUrlEncoded
fun executePost(@FieldMap maps: Map<String, Any>): Call<Any>
}