1. 概述
Retrofit是一个适用于Android和Java的类型安全的HTTP客户端-由Square(Dagger、Okhttp)开发。
在本文中,我们将解释如何使用Retrofit,重点介绍其最有趣的功能。更重要的是,我们将讨论同步和异步API、如何将其用于身份验证、日志记录以及一些良好的建模实践。
2. 设置示例
我们首先添加Retrofit库和Gson转换器:
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-gson</artifactId>
<version>2.3.0</version>
</dependency>
要获取最新版本,请查看Maven Central仓库中的Retrofit和converter-gson。
3. API建模
Retrofit将REST端点建模为Java接口,使其非常易于理解和使用。
我们将从GitHub建模用户API:;它有一个GET端点,以JSON格式返回以下内容:
{
login: "mojombo",
id: 1,
url: "https://api.github.com/users/mojombo",
...
}
Retrofit的工作原理是在基本URL上进行建模并让接口从REST端点返回实体。
为了简单起见,我们将通过建模我们的User类来获取JSON的一小部分,该类将在收到值时获取这些值:
public class User {
private String login;
private long id;
private String url;
// ...
// standard getters an setters
}
可以看到,我们在此示例中仅采用了属性的子集。Retrofit不会抱怨缺少属性-因为它只映射我们需要的属性,即使我们添加JSON中没有的属性,它也不会抱怨。
现在我们可以转到接口建模,并解释一些Retrofit注解:
public interface UserService {
@GET("/users")
public Call<List<User>> getUsers(
@Query("per_page") int per_page,
@Query("page") int page);
@GET("/users/{username}")
public Call<User> getUser(@Path("username") String username);
}
注解提供的元数据足以让该工具生成有效的实现。
@GET注解告诉客户端在哪个资源上使用哪种HTTP方法,例如,通过提供“https://api.github.com”的基本URL,它将把请求发送到“https://api.github.com/users”。
我们的相对URL上的前导“/”告诉Retrofit它是主机上的绝对路径。
另一件需要注意的事情是,我们使用完全可选的@Query参数,如果不需要它们,可以将其传递为null,如果它们没有值,工具将负责忽略这些参数。
最后但同样重要的一点是,@Path让我们指定一个路径参数,该参数将代替我们在路径中使用的标记。
4. 同步/异步API
为了构建HTTP请求调用,我们首先需要构建我们的Retrofit对象:
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.client(httpClient.build())
.build();
Retrofit提供了一个方便的构建器来构建我们所需的对象,它需要一个用于每次服务调用的基本URL和一个转换器工厂-后者负责解析我们发送的数据以及我们得到的响应。
在这个例子中,我们将使用GsonConverterFactory,它将把我们的JSON数据映射到我们之前定义的User类。
需要注意的是,不同的工厂有不同的用途,因此请记住,我们还可以使用XML、原型缓冲区的工厂,甚至可以为自定义协议创建一个工厂。有关已实现工厂的列表,我们可以在此处查看。
最后一个依赖是OKHttpClient-这是适用于Android和Java应用程序的HTTP和HTTP/2客户端,它将负责连接到服务器以及发送和检索信息。我们还可以为每个调用添加标头和拦截器,我们将在身份验证部分中看到这些。
现在我们有了Retrofit对象,可以构造我们的服务调用,让我们看看如何以同步方式执行此操作:
UserService service = retrofit.create(UserService.class);
Call<User> callSync = service.getUser("eugenp");
try {
Response<User> response = callSync.execute();
User user = response.body();
} catch (Exception ex) { ... }
在这里,我们可以看到Retrofit如何根据我们之前的注解,通过注入发出请求所需的代码来构建我们的服务接口。
之后,我们得到一个Call<User>对象,它是用于执行对GitHub API的请求的对象。这里最重要的方法是execute,它用于同步执行调用,并在传输数据时会阻塞当前线程。
调用成功执行后,我们可以借助GsonConverterFactory检索响应主体–已经在用户对象上。
进行同步调用非常简单,但通常我们使用非阻塞异步请求:
UserService service = retrofit.create(UserService.class);
Call<User> callAsync = service.getUser("eugenp");
callAsync.enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
User user = response.body();
}
@Override
public void onFailure(Call<User> call, Throwable throwable) {
System.out.println(throwable);
}
});
现在,我们不再使用execute方法,而是使用enqueue方法-该方法以Callback<User>接口作为参数来处理请求的成功或失败。请注意,这将在单独的线程中执行。
调用成功结束后,我们可以按照之前的方式检索正文。
5. 创建可重用的ServiceGenerator类
现在我们已经了解了如何构造Retrofit对象以及如何使用API,但是我们不想一遍又一遍地编写构建器。
我们想要的是一个可重用的类,它允许我们创建一次该对象并在应用程序的整个生命周期内重复使用它:
public class GitHubServiceGenerator {
private static final String BASE_URL = "https://api.github.com/";
private static Retrofit.Builder builder
= new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create());
private static Retrofit retrofit = builder.build();
private static OkHttpClient.Builder httpClient
= new OkHttpClient.Builder();
public static <S> S createService(Class<S> serviceClass) {
return retrofit.create(serviceClass);
}
}
所有创建Retrofit对象的逻辑现在都移到了这个GitHubServiceGenerator类中,这使其成为一个可持续的客户端类,从而可以避免代码重复。
这是一个如何使用它的简单示例:
UserService service = GitHubServiceGenerator.createService(UserService.class);
现在,如果我们要创建一个RepositoryService,我们可以重用该类并简化创建。
在下一节中,我们将扩展它并添加身份验证功能。
6. 身份验证
大多数API都具有某种身份验证来确保访问的安全。
考虑到我们之前的生成器类,我们将添加一个createService方法,该方法接收带有授权标头的JWT令牌:
public static <S> S createService(Class<S> serviceClass, final String token ) {
if ( token != null ) {
httpClient.interceptors().clear();
httpClient.addInterceptor( chain -> {
Request original = chain.request();
Request request = original.newBuilder()
.header("Authorization", token)
.build();
return chain.proceed(request);
});
builder.client(httpClient.build());
retrofit = builder.build();
}
return retrofit.create(serviceClass);
}
为了在请求中添加标头,我们需要使用OkHttp的拦截器功能;我们通过使用之前定义的构建器并重建Retrofit对象来实现此目的。
请注意,这是一个简单的身份验证示例,但使用拦截器我们可以使用任何身份验证,例如OAuth、用户/密码等。
7. 日志记录
在本节中,我们将进一步扩展GitHubServiceGenerator的日志记录功能,这对于每个项目中的调试目的都非常重要。
我们将使用以前对拦截器的知识,但我们需要一个额外的依赖,即来自OkHttp的HttpLoggingInterceptor,让我们将它添加到我们的pom.xml中:
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>logging-interceptor</artifactId>
<version>5.0.0-alpha.12</version>
</dependency>
现在让我们扩展我们的GitHubServiceGenerator类:
public class GitHubServiceGenerator {
private static final String BASE_URL = "https://api.github.com/";
private static Retrofit.Builder builder
= new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create());
private static Retrofit retrofit = builder.build();
private static OkHttpClient.Builder httpClient
= new OkHttpClient.Builder();
private static HttpLoggingInterceptor logging
= new HttpLoggingInterceptor()
.setLevel(HttpLoggingInterceptor.Level.BASIC);
public static <S> S createService(Class<S> serviceClass) {
if (!httpClient.interceptors().contains(logging)) {
httpClient.addInterceptor(logging);
builder.client(httpClient.build());
retrofit = builder.build();
}
return retrofit.create(serviceClass);
}
public static <S> S createService(Class<S> serviceClass, final String token) {
if (token != null) {
httpClient.interceptors().clear();
httpClient.addInterceptor( chain -> {
Request original = chain.request();
Request.Builder builder1 = original.newBuilder()
.header("Authorization", token);
Request request = builder1.build();
return chain.proceed(request);
});
builder.client(httpClient.build());
retrofit = builder.build();
}
return retrofit.create(serviceClass);
}
}
这是我们类的最终形式,我们可以看到如何添加HttpLoggingInterceptor,并将其设置为基本日志记录,它将记录发出请求所花费的时间、端点、每个请求的状态等。
看看我们如何检查拦截器是否存在是很重要的,这样我们就不会意外地添加它两次。
8. 总结
在这份详尽的指南中,我们通过关注其同步/异步API以及建模、身份验证和日志记录的一些最佳实践来了解优秀的Retrofit库。
Post Directory
