Retrofit是一个适用于 AndroidJava 的类型安全的 HTTP 客户端,它是对OkHttp的封装。

OkHttp请求网络

单独使用OkHttp的时候,我们是这样用的:

val client = OkHttpClient()
val body = RequestBody.create(MediaType.get("text/plain"),"content")
val request = Request.Builder()
    .url("https://www.wanandroid.com/article/list/1/json")
    .post(body)
    .build()
val call = client.newCall(request)
call.enqueue(object : Callback {
    override fun onResponse(call: okhttp3.Call, response: okhttp3.Response) {
        //解析结果response.body(),线程切换
    }
    override fun onFailure(call: okhttp3.Call, e: IOException) {
    }
})

  1. 实例化OkHttpClient对象。
  2. 使用Request.Builder实例化Request对象,同时设置请求地址,参数,方式等。
  3. 获取Call对象,
  4. 使用Call对象发起请求,

经过上面四步就可以获取到服务端返回的数据了,但是OkHttp发起请求的时候新开了线程,而且回调也不在原线程,在Android中我们还需要手动线程切换,切换到UI线程才能展示数据,而且通过response.body()获取到的结果是String类型,往往我们需要的是一个实体对象,这就需要我们再手动格式化一遍。在第二步创建Request对象的时候,我们需要设置url,请求方式,header等参数,非常繁琐。

鉴于以上不方便的地方,Retrofit应运而生。

Retrofit请求网络

val retrofit =  Retrofit.Builder()
    .baseUrl("https://www.wanandroid.com/")
    .addConverterFactory(GsonConverterFactory.create())
    .build()
val appService = retrofit.create(AppService::class.java)
runBlocking {
    val list = appService.list()
    println(Thread.currentThread().name)//main
    println(list.data)
}

  1. 构建 retrofit 实例。
  2. 构建 APIService 接口实例。
  3. 执行请求,解析响应。

两种请求方式最大的区别在于请求的构建和结果的处理。

在OkHttp中,我们是用构建者模式创建Request,而在Retrofit中则是使用@GET,@Header这样的注解。

在OkHttp中我们处理响应的数据需要手动序列化,而且显示在UI界面上还需要手动切换线程,在Retrofit序列化数据仅仅需要添加ConverterFactory就可以了,而且得益于对Kotlin挂起函数的支持,线程也是自动切换。

Retrofit注解

请求方法类注解

Retrofit支持下面八种HTTP请求方法注解@GET,@POST,@PUT,@DELETE,@HEAD,@PATCH,@OPTIONS,@HTTP,@HTTP注解支持自定义请求方法,我们可以使用它实现前面七种注解。

@GET("xxxxx")
suspend fun test(): List<String>

以@GET为例,它接受一个字符串作为参数,表示接口的路径,和BaseUrl一起拼接成完整的地址。

@GET("xxxxx/{userId}")
suspend fun test(@Path("userId") userId: Int): List<String>

注解的参数中可以接受占位符,具体值由@Path指定。

标记类注解

Retrofit提供了@Streaming@FormUrlEncoded@Multipart三种标记类注解。

  • @Streaming 使用该注解之后,响应体的数据用流的形式返回,在现在文件的时候如果不使用该注解,数据就会全部加载到内存,极易造成OOM。
  • @FormUrlEncoded 表示请求体是Form表单,此时Content-Type的值变为application/x-www-form-urlencoded
  • @Multipart 表示请求体是一个支持文件上传的Form表单,此时Content-Type的值变为multipart/form-data

参数类注解

@Headers

@Headers用于配置请求头信息,可以设置多个,该注解作用于方法。

@Headers({"h1: h1", "h2: h2"})
@GET("xxxxx")
suspend fun test(): List<String>

@Header可以用于动态设置请求头信息,作用于参数

@GET("xxxxx")
suspend fun test(@Header("h3") h:String): List<String>

@Query

@Query和@QueryMap用于设置查询参数,一般和@GET一起使用。不同的是@QueryMap接受的参数是一个Map。

@GET("xxxxx")
suspend fun test(@Query("name") name:String): List<String>

@Field

@Field和@FieldMap用于发送POST请求的时候设置表单参数,需要和@FormUrlEncoded一起使用。

@FormUrlEncoded
@POST("xxxxx")
suspend fun test(@Field("name") name:String): List<String>

@Part

@Part和@PartMap用于表单字段参数,适用于文件上传,需要配合Multipart使用。

@Multipart
@POST("xxxxx")
suspend fun uploadImage(@Part img:MultipartBody.Part): List<String>

@Body

@Body将实体类或者Map转化为字符串传给服务端。

@POST("xxxxx")
suspend fun test(@Body body:RequestBody): List<String>
//创建RequestBody
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);

@Url

@Url用于动态指定请求路径。

@GET
suspend fun test(@Url url:String): List<String>

@Path

@Path 用于填充URL地址的缺省值。

@GET("xxxxx/{userId}")
suspend fun test(@Path("userId") userId: Int): List<String>