Integrando Retrofit com RxJava
1. Visão geral
Este artigo se concentra em como implementar um cliente RESTRxJava-ready simples usandoRetrofit.
Vamos construir um aplicativo de exemplo interagindo com a API do GitHub - usando a abordagem de Retrofit padrão e, em seguida, vamos aprimorá-lo usando RxJava para aproveitar as vantagens da Programação Reativa.
2. Retrofit Simples
Vamos primeiro construir um exemplo com Retrofit. Usaremos as APIs do GitHub para obter uma lista classificada de todos os contribuidores que possuem mais de 100 contribuições em qualquer repositório.
2.1. Dependências do Maven
Para iniciar um projeto com Retrofit, vamos incluir estes artefatos Maven:
com.squareup.retrofit2
retrofit
2.3.0
com.squareup.retrofit2
converter-gson
2.3.0
Para as versões mais recentes, dê uma olhada emretrofiteconverter-gson no repositório Maven Central.
2.2. Interface API
Vamos criar uma interface simples:
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);
}
O métodolistRepos() recupera uma lista de repositórios para um determinado usuário passado como um parâmetro de caminho.
O métodolistRepoContributers() recupera uma lista de contribuidores para um determinado usuário e repositório, ambos passados como parâmetros de caminho.
2.3. Lógica
Vamos implementar a lógica necessária usando objetos RetrofitCall e código Java normal:
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. Integrando com RxJava
O retrofit permite receber resultados de chamadas com manipuladores personalizados em vez do objetoCall normal usando adaptadores RetrofitCall. Isso torna possível usar RxJavaObservableseFlowables aqui.
3.1. Dependências do Maven
Para usar o adaptador RxJava, precisamos incluir este artefato Maven:
com.squareup.retrofit2
adapter-rxjava
2.3.0
Para a versão mais recente, verifiqueadapter-rxjava no repositório central Maven.
3.2. Registrar adaptador de chamada RxJava
Vamos adicionarRxJavaCallAdapter ao construtor:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
3.3. Interface API
Neste ponto, podemos alterar o tipo de retorno dos métodos de interface para usarObservable<…> em vez deCall<…>. Podemos usar outros tipos de Rx comoObservable,Flowable,Single,Maybe,Completable.
Vamos modificar nossa interface de API para usarObservable:
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. Lógica
Vamos implementá-lo usando 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. Conclusão
Comparando o código antes e depois de usar RxJava, descobrimos que ele foi aprimorado das seguintes maneiras:
-
Reativo - como nossos dados agora fluem em fluxos, ele nos permite fazer processamento de fluxo assíncrono com contrapressão sem bloqueio
-
Claro - devido à sua natureza declarativa
-
Conciso - toda a operação pode ser representada como uma cadeia de operações
Todo o código neste artigo está disponívelover on GitHub.
O pacotecom.example.retrofit.basic contém o exemplo de retrofit básico, enquanto o pacotecom.example.retrofit.rx contém o exemplo de retrofit com integração RxJava.