Integrazione di Retrofit con RxJava

1. Panoramica

Questo articolo si concentra su come implementare un semplice client REST pronto per RxJava utilizzando Retrofit.

Costruiremo un'applicazione di esempio che interagisce con l'API GitHub, utilizzando l'approccio Retrofit standard, quindi la miglioreremo utilizzando RxJava per sfruttare i vantaggi della programmazione reattiva.

2. Retrofit semplice

Costruiamo prima un esempio con Retrofit. Useremo le API di GitHub per ottenere un elenco ordinato di tutti i contributori che hanno più di 100 contributi in qualsiasi repository.

2.1. Dipendenze di Maven

Per avviare un progetto con Retrofit, includiamo questi artefatti Maven:

 com.squareup.retrofit2 retrofit 2.3.0   com.squareup.retrofit2 converter-gson 2.3.0 

Per le ultime versioni, dai un'occhiata a retrofit e converter-gson nel repository Maven Central.

2.2. Interfaccia API

Creiamo una semplice interfaccia:

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); }

Il metodo listRepos () recupera un elenco di repository per un dato utente passato come parametro di percorso.

Il metodo listRepoContributers () recupera un elenco di contributori per un dato utente e repository, entrambi passati come parametri di percorso.

2.3. Logica

Implementiamo la logica richiesta utilizzando gli oggetti Retrofit Call e il normale codice Java:

class GitHubBasicService { private GitHubBasicApi gitHubApi; GitHubBasicService() { Retrofit retrofit = new Retrofit.Builder() .baseUrl("//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. Integrazione con RxJava

Retrofit ci consente di ricevere i risultati delle chiamate con gestori personalizzati invece del normale oggetto Call utilizzando adattatori di chiamata Retrofit . Questo rende possibile l'uso di RxJava osservabili e compositi fluidi qui.

3.1. Dipendenze di Maven

Per utilizzare l'adattatore RxJava, dobbiamo includere questo artefatto Maven:

 com.squareup.retrofit2 adapter-rxjava 2.3.0 

Per l'ultima versione, controlla adapter-rxjava nel repository centrale di Maven.

3.2. Registra RxJava Call Adapter

Aggiungiamo RxJavaCallAdapter al builder:

Retrofit retrofit = new Retrofit.Builder() .baseUrl("//api.github.com/") .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build();

3.3. Interfaccia API

A questo punto, possiamo modificare il tipo restituito dei metodi di interfaccia per utilizzare Observable anziché Call . Possiamo utilizzare altri tipi di Rx come Observable , Flowable , Single , Forse , Completable .

Modifichiamo la nostra interfaccia API per utilizzare 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. Logica

Implementiamolo usando RxJava:

class GitHubRxService { private GitHubRxApi gitHubApi; GitHubRxService() { Retrofit retrofit = new Retrofit.Builder() .baseUrl("//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. Conclusione

Confrontando il codice prima e dopo aver utilizzato RxJava, abbiamo scoperto che è stato migliorato nei seguenti modi:

  • Reattivo: poiché i nostri dati ora fluiscono nei flussi, ci consente di eseguire l'elaborazione dei flussi asincrona con una contropressione non bloccante
  • Chiaro - a causa della sua natura dichiarativa
  • Conciso: l'intera operazione può essere rappresentata come una catena di operazioni

Tutto il codice in questo articolo è disponibile su GitHub.

Il pacchetto com.baeldung.retrofit.basic contiene l'esempio di retrofit di base mentre il pacchetto com.baeldung.retrofit. rx contiene l'esempio di retrofit con l'integrazione RxJava.