作者: weiyf
时间: 2016/5/15 15:04:25

什么是Retrofit

官方将Retrofit描述为:

A type-safe REST client for Android and Java.

Retrofit将你的HTTP API转变为一个Java接口。

1
2
3
4
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}

Retrofit会自动生成一个GitHubService接口的一个实现类。

1
2
3
4
5
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();

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

每一个从GitHubService生成的Call都可以向远程服务器做一个同步或者异步的请求。

1
Call<List<Repo>> repos = service.listRepos("octocat");

你将使用注解来描述一个HTTP请求。默认集成了URL参数的替换和查询参数的支持。Request Body可以通过转换器转化为一个对象(例如:JSON,protocol buffers等)。
另外,它还提供了multipart request body和文件上传的功能。

如何声明一个请求(API)

REQUEST METHOD

每一个方法都需要有一个提供请求方法和相对路径的HTTP注解。Retrofit给我们提供了五个内置的注解:GETPOST, PUT, DELETE, 和HEAD。 资源的相对路径可以在这些注解中指定。

1
@GET("users/list")

当然, 你也可以在URL中指定请求参数

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

URL MANIPULATION

在方法中, 一个请求可以动态的替换块和参数来进行更新URL。一个替换块就是被{}包围着的字母数字字符串。对应的参数必须使用相同的字符串用@Path来注解。

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

当然, 查询参数也可以被添加。

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

对于复杂的查询参数组合, 也可以放在Map中使用。

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

REQUEST BODY

可以使用@Body注解来指定一个对象作为request body来使用。

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

Retrofit实例中,这个对象会被指定的转换器转换。如果没有添加任何转换器, 则只有RequestBody可以使用了。

FORM ENCODED AND MULTIPART

方法也可以被声明为发送form-encodedmultipart data。 当@FormUrlEncoded在方法体中存在时,数据就会作为form-encoded发送。每一个键值对和对象被它们所提供的值作为名字的@Field所注解。

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

@Multipart在方法体中存在的时候,数据也会被作为Multipart requests发送。Parts使用@Part注解来声明。

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

Multipart part会使用Retrofit中的一个转换器或者一个实现RequestBody来处理自己的序列化。

HEADER MANIPULATION

你可以使用@Headers注解来为方法设置静态的headers

1
2
3
@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
Call<List<Widget>> widgetList();
1
2
3
4
5
6
@Headers({
"Accept: application/vnd.github.v3.full+json",
"User-Agent: Retrofit-Sample-App"
})
@GET("users/{username}")
Call<User> getUser(@Path("username") String username);

需要注意的是, 所添加的Header不会复写其他的Header,所有的headers会使用相同的名字包含在请求当中。

可以使用@Header注解来动态更新一个请求中的Header。必须提供一个对应的参数给@Header。但如果这个值为null,则这个header会被省略。除此之外,这个值会调用其toString方法并使用此结果。

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

需要添加在每一个请求的Headers可以指定一个OKHttp interceptor(拦截器)

SYNCHRONOUS VS. ASYNCHRONOUS

Call实例可以同步或异步执行。每一个实例只能使用一次,但是可以调用clone()方法创建一个新的实例来使用。
在Android中, 回调会在主线程中执行。在JVM中, 回调会发生在和HTTP请求的同一个线程中。

准备你的Android项目

光说不练假把式。如果你已经创建了Android项目,你可以跳过这一节往下看。Else,在你喜欢的IDE创建一个Android项目,我建议使用Gradle作为构建系统和使用 Android Studio作为IDE,或者你觉得其他你会使用得更6!

确定依赖:Gradle or Maven

现在我们可以让你的项目依赖Refrofit,选择你的构建系统和定义Refrofit和它的其他依赖在你的pom.xml或者build.gradle。当运行构建代码的命令的时候,构建系统会为你的项目提供和下载依赖库。
pom.xml

1
2
3
4
5
6
7
8
9
10
<dependency>  
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-gson</artifactId>
<version>2.0.2</version>
</dependency>

build.gradle

1
2
3
4
5
dependencies {  
// Retrofit & OkHttp
compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
}

至发稿前retrofit最新版本为2.0.2

Retrofit 2默认使用OkHttp作为网络层并且是在其之上建立的。你并不需要再次在你的项目中声明OkHttp作为依赖,除非你要使用OkHttp的特定版本。

build.gradle

1
2
3
4
5
6
dependencies {  
compile(rootProject.ext.dependencies['retrofit']) {
exclude module: 'okhttp'
}
compile 'com.squareup.okhttp3:okhttp:3.2.0'
}

现在你的项目已经成功集成Retrofit了。我们可以去创建一个持久的Android API/Http client。

Service Generator

Service Generator是我们API/Httpclient的核心部分。现在看来, 它只是定义了一个为给定的类或接口创建基础的REST设配器的方法。Here is the code :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class ServiceGenerator {

public static final String API_BASE_URL = "http://your.api-base.url";

private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();

private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create());

public static <S> S createService(Class<S> serviceClass) {
Retrofit retrofit = builder.client(httpClient.build()).build();
return retrofit.create(serviceClass);
}
}

这个ServiceGenerator类使用了Retrofit的RestAdapter-Builder来创建一个使用给定的API base url新的REST client,例如:GitHub的API的base url是https://api.github.com/。这个serviceClass定义一个API请求注解类或接口。在接下来的章节中会展示Retrofit的具体用法和如何定义一个范例client。

JSON 映射

但你在使用Retrofit2的时候,你需要在Retrofit项目中明确的添加一个转换器。现在,我们可以为Retrofit 2在我们的build.gradle文件中引入GSON的转换器。

1
compile 'com.squareup.retrofit2:converter-gson:2.0.2'

现在你必须添加转换器到你的Retrofit对象。在Retrofit的builder整合Call.addConverterFactory(GsonConverterFactory.create())使用GSON作为JSON的默认转换器。

Retrofit的使用

那么我们现在面对一个例子来定义一个REST client来向GitHub请求数据。首先,我们需要创建一个接口,并定义所需要的方法。

GitHub Client

下面的代码是定义一个GitHubClient接口和一个方法来请求GitHub上的一个库的贡献者列表。这个例子也说明了Retrofit的参数替换的用法(在路径中定义的{owner}和{repo}会被调用这个方法的变量替换掉)。

1
2
3
4
5
6
7
public interface GitHubClient {  
@GET("/repos/{owner}/{repo}/contributors")
Call<List<Contributor>> contributors(
@Path("owner") String owner,
@Path("repo") String repo
);
}

这定义了一个Contributor类。这个类包含了来响应请求数据映射所需的类属性。

1
2
3
4
static class Contributor {  
String login;
int contributions;
}

对于上面所提到的JSON映射:GitHubClient声明了一个名为contributors的方法,这个方法返回了一个List<Contributor>类型的数据。Retrofit确保了服务器的response被正确映射(如果返回的response匹配给定的类的话)。
下面的代码片段说明了ServiceGenerator如何去实例化你的client的步骤。具体的GitHub client和在创建的client取得贡献者列表的方法。
当你执行这个GitHub例子的时候,你需要手动在ServiceGenerator里面去定义base url的值为"https://api.github.com/"另外一个选择是创建一个额外的CreateService()方法来接受两个参数:client类和base url。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static void main(String... args) {  
// Create a very simple REST adapter which points the GitHub API endpoint.
GitHubClient client = ServiceGenerator.createService(GitHubClient.class);

// Fetch and print a list of the contributors to this library.
Call<List<Contributor>> call =
client.contributors("fs_opensource", "android-boilerplate");

try {
List<Contributor> contributors = call.execute().body();
} catch (IOException e) {
// handle errors
}

for (Contributor contributor : contributors) {
System.out.println(
contributor.login + " (" + contributor.contributions + ")");
}
}

参考链接:https://futurestud.io/blog/retrofit-getting-started-and-android-client