Intégration de Retrofit avec RxJava

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.