Перейти к основному содержимому

Интеграция модернизации с RxJava

· 3 мин. чтения

1. Обзор

В этой статье основное внимание уделяется тому, как реализовать простой REST-клиент с поддержкой RxJava с помощью Retrofit .

Мы создадим пример приложения, взаимодействующего с GitHub API, используя стандартный подход к модернизации, а затем усовершенствуем его с помощью RxJava, чтобы использовать преимущества реактивного программирования.

2. Обычная модернизация

Давайте сначала создадим пример с Retrofit. Мы будем использовать API-интерфейсы GitHub, чтобы получить отсортированный список всех участников, которые имеют более 100 вкладов в любом репозитории.

2.1. Зависимости Maven

Чтобы начать проект с 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>

Последние версии см. в разделе retrofit и convert-gson в репозитории Maven Central.

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() извлекает список репозиториев для данного пользователя, переданного в качестве параметра пути.

Метод listRepoContributers() извлекает список участников для данного пользователя и репозитория, которые передаются как параметры пути.

2.3. Логика

Давайте реализуем необходимую логику, используя объекты 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. Интеграция с RxJava

Retrofit позволяет нам получать результаты вызовов с помощью настраиваемых обработчиков вместо обычного объекта Call с помощью адаптеров Retrofit Call . Это позволяет использовать здесь RxJava Observables и Flowables .

3.1. Зависимости Maven

Чтобы использовать адаптер RxJava, нам нужно включить этот артефакт Maven:

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

Для получения последней версии проверьте adapter-rxjava в центральном репозитории Maven.

3.2. Зарегистрировать адаптер вызова RxJava

Добавим в билдер RxJavaCallAdapter :

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

3.3. API-интерфейс

На этом этапе мы можем изменить возвращаемый тип методов интерфейса, чтобы использовать Observable<…> вместо Call<…> . Мы можем использовать другие типы Rx, такие как Observable , Flowable , Single , Maybe , Completable .

Давайте изменим наш интерфейс 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. Логика

Давайте реализуем это с помощью 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. Вывод

Сравнив код до и после использования RxJava, мы обнаружили, что он был улучшен следующим образом:

  • Реактивный — поскольку наши данные теперь передаются потоками, это позволяет нам выполнять асинхронную потоковую обработку с неблокирующим обратным давлением.
  • Ясно - из-за его декларативного характера
  • Краткость – вся операция может быть представлена как одна цепочка операций

Весь код в этой статье доступен на GitHub.

Пакет com.foreach.retrofit.basic содержит базовый пример модернизации, а пакет com.foreach.retrofit. rx содержит пример модернизации с интеграцией RxJava.