In diesem Artikel wird
RxJava2 in
RxJava2 Version
2.0.6 und
RxJava2 2.0.6 . Wenn jemand zusammengestoßen ist und es nicht herausfinden kann oder überhaupt nichts von diesem Problem gehört hat, bitte ich um eine Katze. Sie veranlassten die Übersetzung von Problemen in der
production nach dem Übergang von
RxJava1 zu
RxJava2 . Das Original wurde am 28. Dezember 2017 geschrieben, aber es ist besser, es spät herauszufinden als nie.
Wir sind alle gute Entwickler und fangen Fehler in
onError wenn wir
RxJava . Das heißt, wir haben uns vor Anwendungsabstürzen geschützt, oder?
Nein, nicht wahr.Im Folgenden werden einige Beispiele aufgeführt, in denen die Anwendung aufgrund von
RxJava , selbst wenn
onError korrekt implementiert ist.
Grundlegende RxJava in RxJava
RxJava verwendet
RxJavaPlugins.onError als
RxJavaPlugins.onError . Es behandelt alle Fehler, die nicht an den Teilnehmer übermittelt werden können. Standardmäßig werden alle Fehler an das Programm gesendet, sodass kritische Anwendungsabstürze auftreten können.
2.0.6 beschreiben dieses Verhalten:
Eines der Ziele des 2.x-Designs ist das Fehlen verlorener Fehler. Manchmal endet eine Sequenz oder wird abgebrochen, bevor die Quelle onError . In diesem Fall kann der Fehler nicht RxJavaPlugins.onError und wird an RxJavaPlugins.onError
Wenn RxJava keinen grundlegenden Fehlerbehandler hat, werden solche Fehler vor uns verborgen und die Entwickler werden über mögliche Probleme im Code im Dunkeln bleiben.
Ab Version
2.0.6 versucht
2.0.6 ,
RxJavaPlugins.onError zu sein, und teilt Bibliotheks- / Implementierungsfehler und Situationen, in denen ein Fehler nicht
RxJavaPlugins.onError werden kann. Fehler, die der Kategorie „Bugs“ zugewiesen sind, werden
UndeliverableException aufgerufen, während der Rest in
UndeliverableException und dann aufgerufen wird. Sie können all diese Logik
hier sehen (
onError und
isBug ).
Einer der
RxJava Neulinge in der
RxJava ist
OnErrorNotImplementedException . Dieser Fehler tritt auf, wenn
observable einen Fehler verursacht und die
onError Methode nicht im Abonnenten implementiert ist. Dieser Fehler ist ein Beispiel für einen Fehler, der für den grundlegenden Fehlerbehandler
RxJava ein "Fehler" ist und nicht zu einer
UndeliverableException .
UndeliverableException
Da Fehler im Zusammenhang mit „Fehlern“ leicht zu beheben sind, werden wir uns nicht mit ihnen befassen. Die Fehler, die
RxJava in eine
RxJava sind interessanter, da möglicherweise nicht immer klar ist, warum der Fehler nicht an
onError .
Die Fälle, in denen dies passieren kann, hängen davon ab, was die Quellen und Abonnenten speziell tun. Wir werden die folgenden Beispiele betrachten, aber im Allgemeinen können wir sagen, dass ein solcher Fehler auftritt, wenn es keinen aktiven Teilnehmer gibt, an den der Fehler geliefert werden kann.
Beispiel mit zipWith ()
Die erste Option, mit der Sie eine
zipWith können, ist die
zipWith .
val observable1 = Observable.error<Int>(Exception()) val observable2 = Observable.error<Int>(Exception()) val zipper = BiFunction<Int, Int, String> { one, two -> "$one - $two" } observable1.zipWith(observable2, zipper) .subscribe( { System.out.println(it) }, { it.printStackTrace() } )
Wir kombinieren zwei Quellen miteinander, von denen jede einen Fehler verursacht. Was erwarten wir? Wir können davon ausgehen, dass
onError zweimal aufgerufen wird, dies widerspricht jedoch
der Spezifikation für Reactive streams .
Nach einem einzelnen Aufruf eines Terminalereignisses ( onError , onCompelete ) müssen keine weiteren Anrufe mehr getätigt werden
Es stellt sich heraus, dass mit einem einzigen Aufruf von
onError zweiter Aufruf nicht mehr möglich ist. Was passiert, wenn ein zweiter Fehler in der Quelle auftritt? Es wird an
RxJavaPlugins.onError geliefert.
Eine einfache Möglichkeit, in diese Situation zu gelangen, besteht darin, Netzwerkanrufe mit
zip zu kombinieren (z. B. zwei
Retrofit Anrufe, die
Observable ). Wenn bei beiden Aufrufen ein Fehler auftritt (z. B. besteht keine Internetverbindung), verursachen beide Quellen Fehler, von denen die erste in die
onError Implementierung fällt und die zweite an den
RxJavaPlugins.onError (
RxJavaPlugins.onError )
RxJavaPlugins.onError .
ConnectableObservable-Beispiel ohne Abonnenten
ConnectableObservable kann auch eine
ConnectableObservable . Es sei daran erinnert, dass
ConnectableObservable Ereignisse unabhängig von der Anwesenheit aktiver Abonnenten
ConnectableObservable Sie einfach die
connect() -Methode auf. Wenn in
ConnectableObservable ein Fehler auftritt, wenn keine Abonnenten vorhanden sind, wird er an den
ConnectableObservable .
Hier ist ein ziemlich unschuldiges Beispiel, das einen solchen Fehler verursachen könnte:
someApi.retrofitCall()
Wenn
someApi.retrofitCall() einen Fehler verursacht (z. B. besteht keine Internetverbindung), stürzt die Anwendung ab, da der Netzwerkfehler an den
RxJava wird.
Dieses Beispiel scheint fiktiv zu sein, aber es ist sehr einfach, in eine Situation zu geraten, in der
ConnectableObservable noch verbunden ist, aber keine Abonnenten hat. Ich bin darauf
autoConnect() als
autoConnect() beim Aufrufen einer API
autoConnect() .
autoConnect() deaktiviert
Observable nicht automatisch. Ich habe die
onStop Activity abgemeldet, aber das Ergebnis des Netzwerkaufrufs, der nach der Zerstörung der
Activity und der Anwendung
UndeliverableException mit
UndeliverableException .
Fehlerbehandlung
Was tun mit diesen Fehlern?
Der erste Schritt besteht darin, die auftretenden Fehler zu untersuchen und festzustellen, was sie verursacht. Ideal, wenn Sie das Problem an der Quelle beheben können, um zu verhindern, dass der Fehler an
RxJavaPlugins.onError .
Die Lösung für das Beispiel
zipWith besteht darin, eine oder beide Quellen zu verwenden und
eine der Methoden zum Abfangen von Fehlern in ihnen zu implementieren. Beispielsweise können Sie
onErrorReturn , um den Standardwert anstelle eines Fehlers zu übergeben.
Das
ConnectableObservable Beispiel ist einfacher zu beheben.
ConnectableObservable Sie lediglich sicher, dass Sie
Observable trennen, wenn sich der letzte Abonnent abmeldet.
autoConnect() verfügt beispielsweise über eine überladene Implementierung, die eine Funktion übernimmt, die die Verbindungszeit
erfasst (
mehr finden Sie hier ).
Eine andere Möglichkeit, das Problem zu lösen, besteht darin, den Basisfehlerbehandler durch Ihren eigenen zu ersetzen. Die
RxJavaPlugins.setErrorHandler(Consumer<Throwable>) hilft Ihnen dabei. Wenn dies die für Sie richtige Lösung ist, können Sie alle an
RxJavaPlugins.onError gesendeten Fehler
RxJavaPlugins.onError und nach
RxJavaPlugins.onError behandeln. Diese Lösung kann sehr kompliziert sein - denken
RxJavaPlugins.onError daran, dass
RxJavaPlugins.onError Fehler von allen
RxJava Streams in der Anwendung empfängt.
Wenn Sie Ihre
Observable manuell erstellen, können Sie
emitter.tryOnError() anstelle von
emitter.tryOnError() . Diese Methode meldet einen Fehler nur, wenn der Stream nicht beendet ist und Abonnenten hat. Denken Sie daran, dass diese Methode experimentell ist.
Die Moral dieses Artikels ist, dass Sie nicht sicher sein können, dass bei der Arbeit mit RxJava keine Fehler auftreten, wenn Sie einfach
onError in Abonnenten implementiert
onError . Sie sollten sich der Situationen bewusst sein, in denen Abonnenten möglicherweise keine Fehler zur Verfügung stehen, und sicherstellen, dass diese Situationen behandelt werden.