1. Обзор
Эта статья посвящена тому, как реализовать простой RxJava-ready REST-клиент с помощью Retrofit .
Мы создадим пример приложения, взаимодействующего с API GitHub, используя стандартный подход к модернизации, а затем улучшим его с помощью RxJava, чтобы использовать преимущества реактивного программирования.
2. Простая Модернизация
Давайте сначала построим пример с Retrofit. Мы будем использовать API GitHub для получения отсортированного списка всех участников, которые имеют более 100 вкладов в любом репозитории.
2.1. Зависимости Maven
Чтобы начать проект с модернизации, давайте включим эти артефакты Maven:
com.squareup.retrofit2 retrofit 2.3.0 com.squareup.retrofit2 converter-gson 2.3.0
Для получения последних версий посмотрите на retrofit и converter-gson в Центральном репозитории Maven.
2.2. Интерфейс API
Давайте создадим простой интерфейс:
public interface GitHubBasicApi { @GET("users/{user}/repos") CalllistRepos(@Path("user") String user); @GET("repos/{user}/{repo}/contributors") Call
listRepoContributors( @Path("user") String user, @Path("repo") String repo); }
Метод list Repos() извлекает список репозиториев для данного пользователя, переданных в качестве параметра path.
Метод list Repo Contributors() извлекает список участников для данного пользователя и репозитория, переданных в качестве параметров пути.
2.3. Логика
Давайте реализуем требуемую логику с помощью Retrofit Call objects и обычного 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); } ListgetTopContributors(String userName) throws IOException { List 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 getContributors(String userName, Repository repo) { List 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:
com.squareup.retrofit2 adapter-rxjava 2.3.0
Для получения последней версии, пожалуйста, проверьте 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> listRepos(@Path("user") String user); @GET("repos/{user}/{repo}/contributors") Observable
> 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); } ObservablegetTopContributors(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.baeldung.retrofit.basic содержит базовый пример модернизации, в то время как пакет com.baeldung.retrofit. rx содержит пример модернизации с интеграцией RxJava.