1. 概述
本文将带你实现一个支持RxJava的REST客户端,使用Retrofit框架。我们将通过GitHub API实战演示:先用传统Retrofit方式实现,再用RxJava进行响应式编程增强。
2. 基础Retrofit实现
先构建一个纯Retrofit的示例:获取任意仓库中贡献超过100次的贡献者排序列表。
2.1 Maven依赖
<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中央仓库:retrofit 和 converter-gson
2.2 API接口定义
public interface GitHubBasicApi {
@GET("users/{user}/repos")
Call<List> listRepos(@Path("user") String user);
@GET("repos/{user}/{repo}/contributors")
Call<List> listRepoContributors(
@Path("user") String user,
@Path("repo") String repo);
}
listRepos()
: 获取指定用户的所有仓库列表listRepoContributors()
: 获取指定仓库的贡献者列表
2.3 业务逻辑实现
class GitHubBasicService {
private GitHubBasicApi gitHubApi;
GitHubBasicService() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
gitHubApi = retrofit.create(GitHubBasicApi.class);
}
List<String> getTopContributors(String userName) throws IOException {
List<Repository> repos = gitHubApi
.listRepos(userName)
.execute()
.body();
repos = repos != null ? repos : Collections.emptyList();
return repos.stream()
.flatMap(repo -> getContributors(userName, repo))
.sorted((a, b) -> b.getContributions() - a.getContributions())
.map(Contributor::getName)
.distinct()
.sorted()
.collect(Collectors.toList());
}
private Stream<Contributor> getContributors(String userName, Repository repo) {
List<Contributor> contributors = null;
try {
contributors = gitHubApi
.listRepoContributors(userName, repo.getName())
.execute()
.body();
} catch (IOException e) {
e.printStackTrace();
}
contributors = contributors != null ? contributors : Collections.emptyList();
return contributors.stream()
.filter(c -> c.getContributions() > 100);
}
}
⚠️ 注意:这种实现存在明显的阻塞调用和冗余的异常处理
3. RxJava集成方案
通过Retrofit的Call Adapter机制,我们可以用RxJava的Observable
替换默认的Call
对象。
3.1 Maven依赖
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>adapter-rxjava</artifactId>
<version>2.3.0</version>
</dependency>
✅ 最新版本请查阅:adapter-rxjava
3.2 注册RxJava适配器
在Retrofit构建器中添加RxJavaCallAdapter
:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
3.3 API接口改造
将返回类型从Call<...>
改为Observable<...>
,支持多种RxJava类型:
public interface GitHubRxApi {
@GET("users/{user}/repos")
Observable<List<Repository>> listRepos(@Path("user") String user);
@GET("repos/{user}/{repo}/contributors")
Observable<List<Contributor>> listRepoContributors(
@Path("user") String user,
@Path("repo") String repo);
}
📌 可选类型:
Observable
,Flowable
,Single
,Maybe
,Completable
3.4 响应式业务逻辑
class GitHubRxService {
private GitHubRxApi gitHubApi;
GitHubRxService() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
gitHubApi = retrofit.create(GitHubRxApi.class);
}
Observable<String> getTopContributors(String userName) {
return gitHubApi.listRepos(userName)
.flatMapIterable(x -> x)
.flatMap(repo -> gitHubApi.listRepoContributors(userName, repo.getName()))
.flatMapIterable(x -> x)
.filter(c -> c.getContributions() > 100)
.sorted((a, b) -> b.getContributions() - a.getContributions())
.map(Contributor::getName)
.distinct();
}
}
✨ 核心优势:
- 完全响应式数据流
- 声明式代码结构
- 操作链式调用
- 内置背压处理
4. 总结
对比传统实现与RxJava集成方案,我们获得三大核心提升:
响应式能力
数据以流的形式传输,支持异步非阻塞处理和背压控制代码清晰度
声明式编程让业务逻辑一目了然,告别回调地狱代码简洁性
整个操作链一气呵成,减少50%+的样板代码
💻 完整代码请参考:GitHub仓库
基础实现路径:com.baeldung.retrofit.basic
RxJava集成路径:com.baeldung.retrofit.rx