Operatoren werden verwendet, um das Problem der Transformation beobachtbarer Objekte zu lösen. Operatoren werden verwendet, um Ereignisse zu ändern, die durch beobachtbares zwischen beobachtbarem und dem endgültigen Abonnenten emittiert werden. Rxjava bietet viele nützliche Betreiber.
Zum Beispiel wird der Kartenoperator verwendet, um ein Ereignis in ein anderes umzuwandeln.
Observable.just ("Hallo, Welt!") .MAP (neuer Func1 <String, String> () {@Override public String call (String s) {return s + "-dan";}}) .SubScribe (s -> system.out.println (s)); Die Verwendung von Lambda kann vereinfacht werden zu
Beobachtbar.just ("Hallo, Welt!") .Map (s -> s + "-dan") .Subscribe (s -> system.out.println (s));Ist es nicht cool? Der MAP () -Operator wird verwendet, um das beobachtbare Objekt zu transformieren. Der Kartenoperator gibt ein beobachtbares Objekt zurück, so dass ein Kettenaufruf implementiert werden kann und der Kartenoperator mehrmals für ein beobachtbares Objekt verwendet wird, und schließlich werden die einfachsten Daten an das Abonnentenobjekt übergeben.
Kartenoperator Fortgeschrittene
Was am Kartenoperator interessanter ist, ist, dass er den vom beobachtbaren Objekt zurückgegebenen Typ nicht zurückgeben muss. Sie können den Kartenoperator verwenden, um ein beobachtbares Objekt zurückzugeben, das den neuen Datentyp ausgibt.
Zum Beispiel kümmert sich der Abonnent im obigen Beispiel nicht um die zurückgegebene Zeichenfolge, möchte aber den Hash -Wert der Zeichenfolge.
Observable.just ("Hallo, Welt!") .MAP (neuer Func1 <String, Integer> () {@Override public Integer Call (String s) {return s.hashCode ();}}) .SubScribe (i -> system.out.println (integer.tostring (i))); Sehr interessant, oder? Unsere anfängliche beobachtbare zurückgibt eine Zeichenfolge, während der endgültige Abonnent eine Ganzzahl erhält. Natürlich kann die Verwendung von Lambda den Code weiter vereinfachen:
Observable.just ("Hallo, Welt!") .Map (S -> S.HashCode ()) .Subscribe (i -> System.out.println (Integer.ToString (i))); Wie bereits erwähnt, desto besser, desto weniger Dinge abonnieren, desto besser. Fügen wir einen weiteren Kartenoperator hinzu.
Observable.just ("Hallo, Welt!") .Map (s -> S.HashCode ()) .Map (i -> Integer Nicht überzeugt?
Denken Sie, dass unser Beispiel zu einfach ist, um Sie zu überzeugen? Sie müssen die folgenden zwei Punkte verstehen:
1. Observable und Abonnent können alles tun
Observable kann eine Datenbankabfrage sein, und der Abonnent wird verwendet, um Abfrageergebnisse anzuzeigen. Observable kann ein Klickereignis auf dem Bildschirm sein, und der Abonnent wird verwendet, um auf Klickereignisse zu reagieren. Observable kann eine Netzwerkanforderung sein, und der Abonnent wird verwendet, um die Anforderungsergebnisse anzuzeigen.
2. Observable und Abonnent sind unabhängig vom Intermediate -Transformationsprozess.
Eine beliebige Anzahl von Karten kann zwischen beobachtbarem und Abonnenten hinzugefügt oder verringert werden. Das gesamte System ist sehr kombinierbar und Betriebsdaten sind ein sehr einfacher Prozess.
Beispiel
1. Vorbereitung
Angenommen, ich habe eine solche Methode:
Diese Methode gibt die URL -Liste einer Website basierend auf der Eingabezeichenfolge (AHHA, Suchmaschine) zurück.
Observable <list <String >> Abfrage (String -Text);
Jetzt möchte ich ein robustes System erstellen, mit dem Zeichenfolgen abfragen und die Ergebnisse angezeigt werden können. Basierend auf dem Inhalt des vorherigen Blogs können wir den folgenden Code schreiben:
Abfrage ("Hallo, Welt!") .Subscribe (URLS -> {für (String url: urls) {System.out.println (url);}});Natürlich kann diese Art von Code nicht toleriert werden, da der obige Code uns dazu veranlasst hat, den Datenfluss zu ändern. Sobald wir jede URL ändern wollen, können wir dies nur im Abonnenten tun. Wir haben keinen so coolen Map () -Operator verwendet! ! !
Natürlich kann ich den Kartenoperator verwenden. Die Eingabe der Karte ist die URLS -Liste. Bei der Verarbeitung muss es noch jeweils durchqueren, was ebenfalls sehr schmerzhaft ist.
Glücklicherweise gibt es auch die beobachtbare Methode. From (), die eine Sammlung als Eingabe empfängt und dann jeweils ein Element an den Abonnenten ausgibt:
Beobachtbar.from ("url1", "url2", "url3") .subscribe (url -> system.out.println (url)); Lassen Sie uns diese Methode gerade jetzt zur Szene verwenden:
Abfrage ("Hallo, Welt!") .Subscribe (URLS -> {Observable.From (urls) .Subscribe (url -> system.out.println (url));});
Obwohl die für jede Schleife entfernt wird, sieht der Code immer noch chaotisch aus. Mehrere verschachtelte Abonnements sehen nicht nur hässlich und schwer zu ändern aus, sondern werden auch einige der Merkmale von Rxjava zerstören, die wir noch nicht erwähnt haben.
2. Verbesserung
Der Erretter ist hier, er ist Flatmap ().
Observable.flatMap () empfängt die Ausgabe eines beobachtbaren als Eingangs und gibt gleichzeitig ein weiteres beobachtbares Ausgang. Schauen Sie sich den Code direkt an:
Query ("Hallo, Welt!") .FlatMap (neuer func1 <list <string>, beobachtbar <string >> () {@Override public Observable <string> call (list <string> urls) {return beobachtbar.from (urls);}}. Hier habe ich den gesamten Funktionscode gepostet, um Ihnen zu verstehen, was los ist. Die Verwendung von Lambda kann die Codelänge erheblich vereinfachen:
Abfrage ("Hallo, Welt!") .FlatMap (URLS -> Observable.From (urls)) .Subscribe (url -> system.out.println (url));Sieht FlatMap () komisch aus? Warum gibt es ein weiteres beobachtbares zurück? Der entscheidende Punkt beim Verständnis von FlatMap ist, dass die neue beobachtbare Ausgabe von FlatMap genau das ist, was wir im Abonnenten erhalten möchten. Jetzt empfängt der Abonnent nicht mehr List <String>, sondern auch einige einzelne Spaltenketten, genau wie die Ausgabe von Observable.from ().
Dieser Teil ist auch der schwierigste Teil, als ich Rxjava zum ersten Mal gelernt habe. Als ich es plötzlich merkte, wurden viele der Fragen in Rxjava gelöst.
3. Es kann besser sein
flatMap () ist wirklich keine bessere Idee, es kann jedes beobachtbare Objekt zurückgeben, das es zurückgeben möchte.
Zum Beispiel die folgende Methode:
// Gibt den Titel der Website zurück, und wenn sie 404 ist, geben Sie NULL Observable <String> Gettitle (String -URL) zurück.
Nach dem vorherigen Beispiel möchte ich die URL nicht mehr drucken, sondern den Titel jeder Website, die ich erhalte. Das Problem ist, dass meine Methode jeweils nur eine URL übergeben kann und der Rückgabewert keine Zeichenfolge, sondern ein Beobachtungsobjekt, das eine Zeichenfolge ausgibt. Die Verwendung von FlatMap () kann dieses Problem einfach lösen.
query ("Hallo, Welt!") .FlatMap (URLS -> Observable.From (urls)) .flatMap (neuer func1 <String, Beobachtbar <String >> () {@Override public Observable <string> call (String url) {return gettitle (url);}}). 4. Verwenden Sie Lambda:
Abfrage ("Hallo, Welt!") .FlatMap (URLS -> Observable.From (URLS)) .FlatMap (URL -> Gettitle (URL)) .SubScribe (Titel -> System.out.println (Titel)); Fühlt es sich nicht unglaublich an? Ich kann tatsächlich mehrere unabhängige Methoden kombinieren, um beobachtbare Objekte gemeinsam zurückzugeben! Sehr gutaussehend!
Darüber hinaus habe ich die Anrufe von zwei APIs zu einem angeketteten Anruf kombiniert. Wir können so viele API -Anrufe so viele wie möglich verknüpfen. Jeder sollte wissen, wie schmerzhaft es ist, alle API -Aufrufe zu synchronisieren und dann die Rückrufergebnisse aller API -Aufrufe in die zu angezeigten Daten zu kombinieren. Hier haben wir die Callback-Hölle erfolgreich vermieden (verschachtelte Rückrufe mit mehreren Schichten, die den Code schwer zu lesen und zu warten). Jetzt ist alle Logik in diesen einfachen reaktionsschnellen Anruf eingebunden.
5. Rich -Operatoren <br /> Bisher sind wir mit zwei Betreibern in Kontakt gekommen, und es gibt mehr Betreiber in Rxjava. Wie können wir also andere Betreiber verwenden, um unseren Code zu verbessern?
Gettitle () gibt NULL zurück, wenn die URL nicht existiert. Wir wollen nicht "null" ausgeben, dann können wir den Nullwert aus der zurückgegebenen Titelliste herausfiltern!
Query ("Hallo, Welt!") .FlatMap (URLS -> Observable.From (urls)) .flatMap (URL -> Gettitle (url)) .filter (title -> title!filter () gibt dieselben Elemente wie Eingabe aus und filtert diejenigen heraus, die die Scheckkriterien nicht erfüllen.
Wenn wir nur bis zu 5 Ergebnisse wollen:
Query ("Hallo, Welt!") .FlatMap (URLS -> Observable.From (urls)) .flatMap (URL -> GetTitle (url)) .filter (title -> title! = null) .take (5).Take () gibt die maximale Anzahl von Ergebnissen aus.
Wenn wir vor dem Drucken jeden Titel auf der Festplatte speichern möchten:
Query ("Hallo, Welt!") .FlatMap (URLS -> Observable.From (urls)) .flatMap (URL -> Gettitle (URL)) .Filter (Titel -Titel!Mit DoonNext () können wir einige zusätzliche Dinge tun, bevor wir jeweils ein Element ausgeben, z. B. das Speichern des Titels hier.
Ist es leicht zu erkennen, wie einfach es ist, den Datenfluss hier zu bedienen? Sie können so viele Vorgänge hinzufügen, wie Sie möchten und Ihren Code nicht durcheinander bringen.
Rxjava enthält eine große Anzahl von Operatoren. Die Anzahl der Operatoren ist etwas beängstigend, aber es lohnt sich, einzeln zu überprüfen, damit Sie wissen, welche Betreiber verwendet werden können. Es mag einige Zeit dauern, diese Betreiber zu verstehen, aber sobald Sie verstehen, werden Sie die Kraft von rxjava vollständig erfassen.
Sie können sogar benutzerdefinierte Operatoren schreiben! Dieser Blog beabsichtigt nicht, den Bediener anzupassen. Wenn Sie möchten, googeln Sie es bitte selbst.
Wie fühlen Sie sich?
Nun, du bist ein Skeptiker und es ist schwer zu überzeugen. Warum kümmerst du dich um diese Betreiber?
Da die Betreiber Sie mit dem Datenstrom etwas tun können.
Durch die Verknüpfung einer Reihe von Operatoren kann eine komplexe Logik erreicht werden. Der Code wird in eine Reihe von Schnipsel unterteilt, die kombiniert werden können. Dies ist der Zauber der reaktiven Funktionsprogrammierung. Je mehr Sie es verwenden, desto mehr werden Sie Ihr Programmieren ändern.
Darüber hinaus erleichtert Rxjava es uns auch, Daten zu verarbeiten. Im letzten Beispiel nennen wir zwei APIs, verarbeiten die von der API zurückgegebenen Daten und speichern sie auf der Festplatte. Aber unser Abonnent weiß das nicht, es glaubt nur, dass er ein beobachtbares <string> -Objekt erhält. Gute Verpackung bringt auch die Codierungsbequemlichkeit!
Im dritten Teil werde ich einige andere coole Funktionen von Rxjava einführen, wie z. B. Fehlerbehebung und Parallelität, die nicht direkt zum Verarbeiten von Daten verwendet werden.