Intégration de Retrofit à RxJava
1. Vue d'ensemble
Cet article se concentre sur la façon d'implémenter un client RESTRxJava-ready simple à l'aide deRetrofit.
Nous allons créer un exemple d'application interagissant avec l'API GitHub - en utilisant l'approche de retrofit standard, puis nous l'améliorerons à l'aide de RxJava pour tirer parti des avantages de la programmation réactive.
2. Rénovation simple
Commençons par créer un exemple avec Retrofit. Nous utiliserons les API GitHub pour obtenir une liste triée de tous les contributeurs qui ont plus de 100 contributions dans n'importe quel référentiel.
2.1. Dépendances Maven
Pour démarrer un projet avec Retrofit, incluons ces artefacts Maven:
com.squareup.retrofit2
retrofit
2.3.0
com.squareup.retrofit2
converter-gson
2.3.0
Pour les dernières versions, jetez un œil àretrofit etconverter-gson sur le référentiel Maven Central.
2.2. Interface API
Créons une interface simple:
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);
}
La méthodelistRepos() récupère une liste de référentiels pour un utilisateur donné passé comme paramètre de chemin.
La méthodelistRepoContributers() récupère une liste de contributeurs pour un utilisateur et un référentiel donnés, tous deux passés comme paramètres de chemin.
2.3. Logique
Implémentons la logique requise à l'aide des objets RetrofitCall et du code 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. Intégration avec RxJava
Retrofit nous permet de recevoir les résultats des appels avec des gestionnaires personnalisés au lieu de l'objet normalCall en utilisant les adaptateurs RetrofitCall. Cela permet d'utiliser ici RxJavaObservables etFlowables.
3.1. Dépendances Maven
Pour utiliser l'adaptateur RxJava, nous devons inclure cet artefact Maven:
com.squareup.retrofit2
adapter-rxjava
2.3.0
Pour la dernière version, veuillez vérifieradapter-rxjava dans le référentiel central Maven.
3.2. Enregistrer l'adaptateur d'appel RxJava
AjoutonsRxJavaCallAdapter au générateur:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
3.3. Interface API
À ce stade, nous pouvons changer le type de retour des méthodes d'interface pour utiliserObservable<…> plutôt queCall<…>. Nous pouvons utiliser d'autres types de Rx commeObservable,Flowable,Single,Maybe,Completable.
Modifions notre interface API pour utiliserObservable:
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. Logique
Implémentons-le en utilisant 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. Conclusion
En comparant le code avant et après l'utilisation de RxJava, nous avons constaté qu'il a été amélioré des manières suivantes:
-
Réactif - dans la mesure où nos données sont maintenant transférées dans des flux, cela nous permet d'effectuer un traitement de flux asynchrone avec une contre-pression non bloquante.
-
Clair - en raison de son caractère déclaratif
-
Concis - toute l'opération peut être représentée comme une chaîne d'opération
Tout le code de cet article est disponibleover on GitHub.
Le packagecom.example.retrofit.basic contient l'exemple de retrofit de base tandis que le packagecom.example.retrofit.rx contient l'exemple de retrofit avec intégration RxJava.