Интеграция модернизации с RxJava
1. обзор
Эта статья посвящена тому, как реализовать простой клиент RESTRxJava-ready с использованиемRetrofit.
Мы создадим пример приложения, взаимодействующего с GitHub API - используя стандартный подход Retrofit, а затем улучшим его с помощью RxJava, чтобы использовать преимущества реактивного программирования.
2. Обычная модернизация
Давайте сначала построим пример с Retrofit. Мы воспользуемся API-интерфейсами GitHub, чтобы получить отсортированный список всех участников, у которых более 100 вкладов в любом репозитории.
2.1. Maven Зависимости
Чтобы начать проект с Retrofit, давайте включим эти артефакты Maven:
com.squareup.retrofit2
retrofit
2.3.0
com.squareup.retrofit2
converter-gson
2.3.0
Последние версии см. Вretrofit иconverter-gson в репозитории Maven Central.
2.2. API интерфейс
Давайте создадим простой интерфейс:
public interface GitHubBasicApi {
@GET("users/{user}/repos")
Call listRepos(@Path("user") String user);
@GET("repos/{user}/{repo}/contributors")
Call listRepoContributors(
@Path("user") String user,
@Path("repo") String repo);
}
МетодlistRepos() извлекает список репозиториев для данного пользователя, переданный в качестве параметра пути.
МетодlistRepoContributers() извлекает список участников для данного пользователя и репозитория, которые передаются как параметры пути.
2.3. логика
Давайте реализуем необходимую логику, используя объекты RetrofitCall и обычный 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 getTopContributors(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 с помощью адаптеров RetrofitCall. Это позволяет использовать здесь RxJavaObservables и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);
}
Observable 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, мы обнаружили, что он был улучшен следующими способами:
-
Реактивный - поскольку наши данные теперь перемещаются в потоках, это позволяет нам выполнять асинхронную потоковую обработку с неблокирующим обратным давлением
-
Ясно - благодаря своей декларативной природе
-
Кратко - вся операция может быть представлена в виде одной цепочки операций
Весь код в этой статье доступенover on GitHub.
Пакетcom.example.retrofit.basic содержит базовый пример модернизации, а пакетcom.example.retrofit.rx содержит пример модернизации с интеграцией RxJava.