Nachrüstung mit RxJava integrieren
1. Überblick
Dieser Artikel befasst sich mit der Implementierung eines einfachenRxJava-ready REST-Clients mitRetrofit.
Wir werden eine Beispielanwendung erstellen, die mit der GitHub-API interagiert - unter Verwendung des Standard-Retrofit-Ansatzes - und sie dann mithilfe von RxJava verbessern, um die Vorteile der reaktiven Programmierung zu nutzen.
2. Einfache Nachrüstung
Lassen Sie uns zunächst ein Beispiel mit Retrofit erstellen. Wir verwenden die GitHub-APIs, um eine sortierte Liste aller Mitwirkenden zu erhalten, die mehr als 100 Beiträge in einem Repository haben.
2.1. Maven-Abhängigkeiten
Um ein Projekt mit Retrofit zu starten, fügen wir folgende Maven-Artefakte hinzu:
com.squareup.retrofit2
retrofit
2.3.0
com.squareup.retrofit2
converter-gson
2.3.0
Die neuesten Versionen finden Sie unterretrofit undconverter-gson im Maven Central-Repository.
2.2. API-Schnittstelle
Erstellen wir eine einfache Oberfläche:
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);
}
Die MethodelistRepos() ruft eine Liste von Repositorys für einen bestimmten Benutzer ab, die als Pfadparameter übergeben wurden.
Die MethodelistRepoContributers()ruft eine Liste der Mitwirkenden für einen bestimmten Benutzer und ein bestimmtes Repository ab, die beide als Pfadparameter übergeben werden.
2.3. Logik
Implementieren wir die erforderliche Logik mithilfe der Objekte von RetrofitCallund normalem Java-Code:
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. Integration in RxJava
Mit Retrofit können wir Anrufergebnisse mit benutzerdefinierten Handlern anstelle des normalenCall-Objekts empfangen, indem wir die Adapter von RetrofitCallverwenden. Dies ermöglicht es, hier RxJavaObservables undFlowables zu verwenden.
3.1. Maven-Abhängigkeiten
Um den RxJava-Adapter verwenden zu können, müssen Sie das folgende Maven-Artefakt einschließen:
com.squareup.retrofit2
adapter-rxjava
2.3.0
Für die neueste Version überprüfen Sie bitteadapter-rxjava im zentralen Maven-Repository.
3.2. Registrieren Sie den RxJava-Anrufadapter
Fügen wir dem BuilderRxJavaCallAdapter hinzu:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
3.3. API-Schnittstelle
Zu diesem Zeitpunkt können wir den Rückgabetyp der Schnittstellenmethoden ändern, umObservable<…> anstelle vonCall<…> zu verwenden. Wir können andere Rx-Typen wieObservable,Flowable,Single,Maybe,Completable verwenden.
Ändern Sie unsere API-Schnittstelle so, dassObservable verwendet werden:
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. Logik
Implementieren wir es mit 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. Fazit
Beim Vergleich des Codes vor und nach der Verwendung von RxJava haben wir festgestellt, dass er auf folgende Weise verbessert wurde:
-
Reaktiv - Da unsere Daten jetzt in Streams fließen, können wir asynchrone Stream-Verarbeitung mit nicht blockierendem Gegendruck durchführen
-
Klar - aufgrund seiner deklarativen Natur
-
Prägnant - Die gesamte Operation kann als eine Operationskette dargestellt werden
Der gesamte Code in diesem Artikel ist inover on GitHub. verfügbar
Das Paketcom.example.retrofit.basic enthält das grundlegende Nachrüstbeispiel, während das Paketcom.example.retrofit.rx das Nachrüstbeispiel mit RxJava-Integration enthält.