Retrofit详解
简介
Retrofit是一个将Http API转化为Java接口,最终将接口转换为 callable 对象,并能执行同步和异步Http请求的Http Client。
具体来讲,使用Retrofit的步骤包括:
- 使用注解来定义Http API的Java接口。
- 定义好接口之后,通过Retrofit实例生成接口实例
- 通过调用接口实例的方法,获取Call对象
- 通过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的注解有一下功能:
- 支持Url参数占位符和查询参数
- 请求体和java对象的转换,这种转换支持多种格式:JSON 、protocol buffers等
- 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个子模块用来支持当下流行的序列化方式:
- Gson: com.squareup.retrofit2:converter-gson
- Jackson: com.squareup.retrofit2:converter-jackson
- Moshi: com.squareup.retrofit2:converter-moshi
- Protobuf: com.squareup.retrofit2:converter-protobuf
- Wire: com.squareup.retrofit2:converter-wire
- Simple XML: com.squareup.retrofit2:converter-simplexml
- 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类即可。