Retrofit:Android 和 Java 类型安全的 HTTP 代理
使用步骤概述:
1. Retrofit 使用一个 Java 接口类来描述一个 HTTP API,每一个接口方法代表着一个 Http 请求:
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
2. 由 Retrofit 类产生一个 GitHubService 接口类的实现:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
3. 调用 GitHubService 中的一个接口方法得到对应的 Call 对象,使用 Call 对象发起一次同步或者异步的 HTTP 请求:
Call<List<Repo>> repos = service.listRepos("octocat");
// 同步 Http 请求
// repos.execute();
// 异步 Http 请求
repos.enqueue(new Callback<List<Repo>>() {
@Override
public void onResponse(@NonNull Call<List<Repo>> call,
@NonNull Response<List<Repo>> response) {
// 我们的数据
ResponseBody data = response.body();
}
@Override
public void onFailure(@NonNull Call<List<Repo>> call,
@NonNull Throwable t) {
}
});
使用注解(Annotation)编写 HTTP 请求的优点:
1. 支持 URL 参数 替换和 查询参数 替换
2. 支持将自己的 JAVA 对象转换为一个 HTTP 请求,(如 JSON 等)
3. 支持 Multipart HTTP 请求和文件上传
API 声明:
Retrofit 使用代表着一个带注解的 Java 接口类来表示 HTTP API,它的每一个接口方法都返回一个可以用来发起请求的 Call 对象,而请求的方式、参数以及请求体都可以由方法上的注解决定
1. 注解确定 –> 请求方法( REQUEST METHOD )
- 每一个接口方法必须由一个 HTTP 注解来标注 请求方法 和 相对 Url,Retrofit 内置的注解有: GET, POST, PUT, DELETE, 和 HEAD. 相对 URL 写在注释的括号中:
@GET("users/list")
- 相对 Url 中可以指出查询参数:
@GET("users/list?sort=desc")
- URL 参数动态替换操作
一个请求的 URL 可以使用 占位符和方法参数 的方式调用时动态替换,占位符是一个由花括号 {} 括起来的英文单词组成,用@PATH
标注并且 注解参数 和花括号中的英文单词一致的参数,发起请求时会被用来替换占位符内容:
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId);
- 也可以动态添加查询参数,发起请求时
@Query
标注的参数(sort_key=sort_value
)将会被添加到 Url 作为请求参数:
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @Query("sort_key") String sort_value);
- 对于更复杂的查询参数,可以时使用 Map 来承载:
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);
2. 注解确定 –> 请求体(REQUEST BODY)
- 使用
@Body
标注的参数可以在发送请求时将被当成 HTTP 请求体
@POST("users/new")
Call<User> createUser(@Body User user);
在构建请求体发起 HTTP 请求之前,这个 user 对象将会被转换(converted)为一个具体的数据实例,如果没有在构建 Retrofit 实例时添加对应的 转换者,默认只能转换为 Okhttp 中的RequestBody
实例
3. 对象转换者(CONVERTERS)
- 上面提到,默认情况下,Retrofit 只能为
@Body
参数接受一个ResponseBody
对象,同样,在响应回调时,也只能将 HTTP 响应转化为 OkHttp 的ResponseBody
对象。
而通过添加转换者(Converters),Retrofit 可以支持多种对象转换,这里官方提供了 6 种对象转换者:
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
这里给出给出一个例子,使用 GsonConverterFactory
转换 GitHubService
接口实例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
// 使用了 GsonConverter
.addConverterFactory(GsonConverterFactory.create())
.build();
GitHubService service = retrofit.create(GitHubService.class);
Call<List<Repo>> repos = service.listRepos("octocat");
// 异步执行
repos.enqueue(new Callback<List<Repo>>() {
@Override
public void onResponse(@NonNull Call<List<Repo>> call
, @NonNull Response<List<Repo>> response) {
// 我们的 JSON 数据直接由 GsonConverter 转化为对应的 JAVA 实体类
List<Repo> repo = response.body();
}
@Override
public void onFailure(@NonNull Call<List<Repo>> call
, @NonNull Throwable t) {
}
});
- 自定义转换者 (CUSTOM CONVERTERS)
如果你需要转换的数据不是以上提供的 6 种,可以通过继承Converter.Factory
来实现自己的转换者。
4. 注解 –> 提交表单数据 和 Multipart (FORM ENCODED AND MULTIPART)
- 接口方法也可以声明为
@FormUrlEncoded
,然后参数使用@Field
标注,表示向服务器提交一份标准的 URL 编码的数据:
@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(
@Field("first_name") String first,
@Field("last_name") String last
);
这样发送出去的表单格式的请求体(form encoded request body)就是:
first_name=first&last_name=last
- 接口方法声明为
@Multipart
,然后参数使用@Part
标注,表示向服务器提交多部分请求(Multipart requests):
@Multipart
@PUT("user/photo")
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);
5. 注解确定 –> 请求头(HEADER MANIPULATION)
- 可以通过
@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);
需要注意的是,每一个请求头都会被添加到 HTTP 请求中,无论他们的名称是否相同。
- 使用
@Header
动态更新请求头,使用@Header
的参数被视为一个请求头,对应请求头的名称要写在注解的括号里,参数的值不能为 null:
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)
原文:http://square.github.io/retrofit/
详细教程:https://futurestud.io/tutorials/retrofit-2-how-to-download-files-from-server