大数据

#Android# Retrofit使用指南

知识框架(脑图)

Retrofit脑图

出现背景

移动端网络请求复杂,代码冗余

解决思路

Retrofit:给Android和Java用的类型安全的HTTP客户端,将网络请求抽象成接口,以注解形式定义HTTP请求,Retrofit会自动生成对应的实现供开发人员调用。

Retrofit设计思路

具体步骤

(1)添加网络访问权限并引入依赖库

compile 'com.squareup.retrofit2:retrofit:2.1.0'

(2)使用注解定义网络访问的API

public interface GitHubService {
  @GET("users/{user}/repos")
  Call> listRepos(@Path("user") String user);
}

有哪些注解呢?

  • URL参数和Query参数
  • 对象到请求体的转换(eg : JSON,protocol buffers)
  • 表单提交和文件上传

Retrofit中的注解

(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> repos = service.listRepos("octocat");
// 同步请求
List 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> groupList(@Path("id") int groupId);

也可以使用@Query注解添加查询参数,如:

@GET("group/{id}/users")
Call> groupList(@Path("id") int groupId, @Query("sort") String sort);

复杂点的查询参数可以结合成一个Map再用,如:

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

(6)进阶:请求体

对象可以作为HTTP的请求体(使用@Body注解),也可以使用转换器转成特定的字符串,比如JSON。

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

(7)进阶:表单提交和文件上传

使用@FormUrlEncoded标明是表单上传的方法,然后每一个键值对使用@Field关联:

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

使用@Multipart标明是文件上传的方法,然后使用@Part分隔各个部分:

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

(8)进阶:操作请求头

使用@Headers设置静态请求头

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

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

注意:请求头不会相互覆盖,同名的请求头会被保留进请求。

可以使用@Header动态修改请求头,如果值是null,那么该头部会被清除;还有toString方法会被调用。

@GET("user")
Call 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对象

参考文档

  1. Retrofit
  2. 用Retrofit2简化HTTP请求
  3. Unable to create converter for java.util.List Retrofit 2.0.0-beta2
  4. Retrofit请求参数注解字段说明