#Android# Retrofit使用指南
知识框架(脑图)
Retrofit脑图出现背景
移动端网络请求复杂,代码冗余
解决思路
Retrofit:给Android和Java用的类型安全的HTTP客户端,将网络请求抽象成接口,以注解形式定义HTTP请求,Retrofit会自动生成对应的实现供开发人员调用。
Retrofit设计思路具体步骤
(1)添加网络访问权限并引入依赖库
<uses-permission android:name="android.permission.INTERNET"/>
compile 'com.squareup.retrofit2:retrofit:2.1.0'
(2)使用注解定义网络访问的API
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
有哪些注解呢?
- URL参数和Query参数
- 对象到请求体的转换(eg : JSON,protocol buffers)
- 表单提交和文件上传
(3)使用Retrofit生成该接口的一个实现
使用Builder构建一个Retrofit,并调用Retrofit的create方法创建一个接口实现。构建的时候需要提供baseUrl,而接口定义时使用相对路径即可。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create()) //这里使用Gson转换器,需要添加相应依赖,见问题1
.build();
GitHubService service = retrofit.create(GitHubService.class);
(4)调用实现的方法来进行同步或异步的HTTP请求
Call<List<Repo>> repos = service.listRepos("octocat");
// 同步请求
List<Repo> repoList = repos.execute().body();
// 异步请求
repos.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
// response.body().string();
}
});
调用接口方法之后返回的是Call对象,可以被异步或同步执行,每个实例只能使用一次,当然可以使用clone()造一个新的来用。还可以通过cancle方法取消Call~
在Android,回调会在主线程执行;而在JVM,回调会在发起HTTP请求的线程执行;这是自动完成的!!
(5)进阶:操作URL
使用替换块和方法中的参数动态地更新请求的URL。替换块的组成:用花括号包裹起来的仅含字母数字的字符串;而参数需要使用@Path注解和相同的字符串。例如:
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId);
也可以使用@Query注解添加查询参数,如:
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);
复杂点的查询参数可以结合成一个Map再用,如:
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);
(6)进阶:请求体
对象可以作为HTTP的请求体(使用@Body注解),也可以使用转换器转成特定的字符串,比如JSON。
@POST("users/new")
Call<User> createUser(@Body User user);
(7)进阶:表单提交和文件上传
使用@FormUrlEncoded标明是表单上传的方法,然后每一个键值对使用@Field关联:
@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
使用@Multipart标明是文件上传的方法,然后使用@Part分隔各个部分:
@Multipart
@PUT("user/photo")
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);
(8)进阶:操作请求头
使用@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);
注意:请求头不会相互覆盖,同名的请求头会被保留进请求。
可以使用@Header动态修改请求头,如果值是null,那么该头部会被清除;还有toString方法会被调用。
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)
(9)进阶:Retrofit配置转换器
为什么要配置转换器?
Retrofit已经不提供给默认的转换器了,需要相应的转换器,比如要用Gson解析的话就需要添加依赖并使用addConverterFactory方法在构建Retrofit时配置好。
有哪些转换器可以用?
- 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
怎么添加转换器?
使用addConverterFactory
方法
// 以添加GsonConverterFactory为例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
GitHubService service = retrofit.create(GitHubService.class);
Q&A
问题1:IllegalArgumentException: Unable to create converter for class...
Retrofit已经不提供给默认的转换器了,需要相应的转换器比如要用Gson解析的话就需要添加依赖:
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
然后构建Retrofit时使用该转换器:
Retrofit client = new Retrofit.Builder()
.baseUrl("https://github.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
值得注意的是:JSON Converter要放置在最后,因为没有确切的条件可以判定一个对象是否是JSON对象。