Retrofit详解

简介

Retrofit是一个将Http API转化为Java接口,最终将接口转换为 callable 对象,并能执行同步和异步Http请求的Http Client。

具体来讲,使用Retrofit的步骤包括:

  1. 使用注解来定义Http API的Java接口。
  2. 定义好接口之后,通过Retrofit实例生成接口实例
  3. 通过调用接口实例的方法,获取Call对象
  4. 通过Call对象,向远程服务器发送同步和异步的Http请求。

示例如下:

//使用注解来定义Http API的Java接口。
public interface GitHubService {

    @GET("users/{user}/repos")
    Call<List<Repo>> listRepos(@Path("user") String user);
}

//定义好接口之后,通过Retrofit实例生成接口实例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);

// 通过调用接口实例的方法,获取Call对象
Call<List<Repo>> repos = service.listRepos("octocat");

Retrofit的注解有一下功能:

  1. 支持Url参数占位符和查询参数
  2. 请求体和java对象的转换,这种转换支持多种格式:JSON 、protocol buffers等
  3. Multipart请求体和文件上传

Http API的声明

Retrofit使用注解来将Http API声明为java接口,这些注解主要作用于接口的方法和参数,它们决定了对应的Http Request如何被处理。

REQUEST METHOD(请求方法)

每一个接口方法,必须有一个Http注解修饰,用来提供请求方法和相对URL。Retrofit提供了五种内置的 HTTP注解 GET, POST, PUT, DELETE, 和 HEAD,每一个注解对应一种请求方法,相对URL作为注解参数。

@GET("users/list")

在声明注解的时候,还可以在URL中声明查询参数:

@GET("users/list?sort=desc")

URL MANIPULATION(Url 操作)

当我们有时候需要动态改变请求的URL的时候,可以在声明接口方法的时候使用 占位块 和参数。占位块是一个使用 {} 包围的字符串,参数是接口中的参数,并且必须使用 @Path 注解修饰参数

使用方式如下:

@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId);

同时,还可以通过 @Query @QueryMap 指定查询参数。

当需要添加单个查询参数时这样使用:

@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId);

当有多个查询参数时,可以使用 @QueryMap注解:

@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);

REQUEST BODY(请求体)

当需要将一个方法参数声明为请求的请求体时,可以使用 @Body 注解 修饰之,

@POST("users/new")
Call<User> createUser(@Body User user);

如果在初始化Retrofit实例的时候指定了Converter实例,那么对象将通过Converter实例转化为请求体,如果没指定,那么默认转化为OkHttp的RequestBody。

FORM ENCODED AND MULTIPART(表单和MULTIPART)

当方法需要用来发送 form-encoded 和 multipart 数据时,可以用 @FormUrlEncoded 和 @Multipart注解声明。

当需要发送 form-encoded 数据时,使用 @FormUrlEncoded声明方法,作为表单数据的键值对使用 @Field注解声明,@Field的参数就是 key 的 名字,@Field修饰的参数的值就是key的值,使用如下:

@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);

当需要发送Multipart数据时,使用 @Multipart声明方法,数据项使用 @Part声明,@Part的参数就是数据项的key,@Part修饰的参数的值就是数据项的值,使用如下:

@Multipart
@PUT("user/photo")
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);

Multipart parts 使用retrofitconverter进行序列化,如果没有指定converter,则使用RequestBody处理序列化。

HEADER MANIPULATION (头部操作)

通过Retrofit对请求的头部进行操作有三种方式: 1. 静态头部 2. 动态头部 3. 通过OkHttp interceptor

前两种方式式通过 各自的 注解来完成的。

添加静态头部

当对于一个方法,需要添加一些固定首部的时候可以使用 @HEADERS 注解,静态添加的方式

添加单个头部:

@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
Call<List<Widget>> widgetList();

添加多个头部:

@Headers({
"Accept: application/vnd.github.v3.full+json",
"User-Agent: Retrofit-Sample-App"
})
@GET("users/{username}")
Call<User> getUser(@Path("username") String username);

头部字段不相互覆盖,当有多个name一样的头部字段时,这些字段都会包含在这个请求里。

添加动态头部

当头部字段需要作为方法的参数动态传递的时候,可以使用 @HEADER 注解,动态添加的方式:

@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)

用 @HEADER 标签修饰的参数,表示该参数值将作为头部字段的值,头部字段的key在注解参数里。使用这种方式,必须为 @HEADER 提供一个对应的参数,如果这个值为 null,那么这个header将被忽略

通过OkHttp interceptor

当对于每一个请求都要添加这样的首部的时候,可以使用这种方式。

同步和异步请求

Call实例能够以异步或者同步的方式执行,每个Call实例只能被执行一次,如果需要重复执行,需要通过clone()方法获取一个新的实例执行之。

在Android中,回调将会在main线程中执行,在JVM上,callback会在发起Http Request的线程中执行。

Retrofit配置

默认情况下,Retrofit提供功能齐全的配置,同时也支持自定义。

在默认情况想,Retrofit只能够将Http Body反序列化成 OkHttp's ResponseBody 类型,同时 只能接受 OkHttp RequestBody类型作为 请求体。

当前序列化库有很多,可以通过添加相应的Converter来支持其他的序列化方式,目前Retrofit提供7个子模块用来支持当下流行的序列化方式:

  1. Gson: com.squareup.retrofit2:converter-gson
  2. Jackson: com.squareup.retrofit2:converter-jackson
  3. Moshi: com.squareup.retrofit2:converter-moshi
  4. Protobuf: com.squareup.retrofit2:converter-protobuf
  5. Wire: com.squareup.retrofit2:converter-wire
  6. Simple XML: com.squareup.retrofit2:converter-simplexml
  7. Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars

使用方式如下:

Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.addConverterFactory(GsonConverterFactory.create())
.build();

GitHubService service = retrofit.create(GitHubService.class);

使用方式很简单,通过给Retrofit实例添加Converter就可以。

当然,如果Retrofit提供的预定义的Converter仍然不能够满足你的需求,你可以自定义Converter,只需要继承 Converter.Factory类即可。