Integrating Retrofit with RxJava – 将Retrofit与RxJava集成

最后修改: 2017年 9月 8日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

This article focuses on how to implement a simple RxJava-ready REST Client using Retrofit.

本文主要介绍如何使用RxJava-readyREST客户端实现一个简单的Retrofit

We’ll build an example application interacting with the GitHub API – using the standard Retrofit approach, and then we’ll enhance it using RxJava to leverage the advantages of Reactive Programming.

我们将建立一个与GitHub API交互的示例应用程序–使用标准的Retrofit方法,然后我们将使用RxJava增强它,以利用反应式编程的优势。

2. Plain Retrofit

2.普通改造

Let’s first build an example with Retrofit. We’ll use the GitHub APIs to get a sorted list of all the contributors that have more than 100 contributions in any repository.

首先让我们用Retrofit建立一个例子。我们将使用GitHub的API来获得一个排序的列表,其中包括在任何仓库中拥有超过100条贡献的所有贡献者。

2.1. Maven Dependencies

2.1.Maven的依赖性

To start a project with Retrofit, let’s include these Maven artifacts:

要用Retrofit启动一个项目,让我们包括这些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>

For the latest versions, have a look at retrofit and converter-gson on Maven Central repository.

关于最新版本,请查看Maven Central资源库中的retrofitconverter-gson

2.2. API Interface

2.2.API接口

Let’s create a simple interface:

让我们创建一个简单的界面。

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);   
}

The listRepos() method retrieves a list of repositories for a given user passed as a path parameter.

listRepos()方法为给定的用户检索一个作为路径参数传递的存储库的列表。

The listRepoContributers() method retrieves a list of contributors for a given user and repository, both passed as path parameters.

listRepoContributers()方法检索给定用户和版本库的贡献者列表,两者都作为路径参数传递。

2.3. Logic

2.3.逻辑

Let’s implement the required logic using Retrofit Call objects and normal Java code:

让我们使用Retrofit Call 对象和普通Java代码来实现所需的逻辑。

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. Integrating With RxJava

3.与RxJava的整合

Retrofit lets us receive calls results with custom handlers instead of the normal Call object by using Retrofit Call adapters. This makes it possible to use RxJava Observables and Flowables here.

Retrofit允许我们通过使用Retrofit Call 适配器来接收带有自定义处理程序的调用结果,而不是普通的Call 对象。这使得在这里使用 RxJava ObservablesFlowables 成为可能。

3.1. Maven Dependencies

3.1.Maven的依赖性

To use RxJava adapter, we need to include this Maven artifact:

要使用RxJava适配器,我们需要包含这个Maven工件。

<dependency>
    <groupId>com.squareup.retrofit2</groupId>
    <artifactId>adapter-rxjava</artifactId>
    <version>2.3.0</version>
</dependency>

For the latest version please check adapter-rxjava in Maven central repository.

最新版本请查看Maven中心资源库中的adapter-rxjava

3.2. Register RxJava Call Adapter

3.2.注册RxJava调用适配器

Let’s add RxJavaCallAdapter to the builder:

让我们把RxJavaCallAdapter添加到构建器中。

Retrofit retrofit = new Retrofit.Builder()
  .baseUrl("https://api.github.com/")
  .addConverterFactory(GsonConverterFactory.create())
  .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
  .build();

3.3. API Interface

3.3.API接口

At this point, we can change the return type of interface methods to use Observable<…> rather than Call<…>. We may use other Rx types like Observable, Flowable, Single, Maybe, Completable.

此时,我们可以改变接口方法的返回类型,使用Observable<…>而不是Call<…>。我们可以使用其他的Rx类型,如ObservableFlowableSingleMaybeCompletable

Let’s modify our API interface to use Observable:

让我们修改我们的API接口以使用Observable

public interface GitHubRxApi {

    @GET("users/{user}/repos")
    Observable<List<Repository>> listRepos(@Path("user") String user);
    
    @GET("repos/{user}/{repo}/contributors")
    Observable<List<Contributer>> listRepoContributors(
      @Path("user") String user,
      @Path("repo") String repo);   
}

3.4. Logic

3.4.逻辑

Let’s implement it using RxJava:

让我们用RxJava来实现它。

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. Conclusion

4.结论

Comparing the code before and after using RxJava, we’ve found that it has been improved in the following ways:

对比使用RxJava之前和之后的代码,我们发现它在以下方面得到了改进。

  • Reactive – as our data now flows in streams, it enables us to do asynchronous stream processing with non-blocking back pressure
  • Clear – due to its declarative nature
  • Concise – the whole operation can be represented as one operation chain

All the code in this article is available over on GitHub.

本文的所有代码都可以在GitHub上找到

The package com.baeldung.retrofit.basic contains the basic retrofit example while the package com.baeldung.retrofit.rx contains the retrofit example with RxJava integration.

com.baeldung.retrofit.basic包含基本的改造实例,而包com.baeldung.retrofit.rx包含集成RxJava的改造实例。