UndeliverableException
in RxJava2
version 2.0.6
and newer. If someone collided and cannot understand, or did not hear at all about this problem - I ask under cat. Prompted to transfer the problem in production
after the transition from RxJava1
to RxJava2
. The original was written on December 28, 2017, but it’s better to learn late than never.onError
when we use RxJava
. This means that we protected ourselves from the application crashes, right?RxJava
, even if onError
correctly implemented.RxJava
RxJava
, RxJavaPlugins.onError
used. It handles all errors that cannot be delivered to the subscriber. By default, all errors are sent exactly to it, so application crashes may occur.2.0.6
this behavior is described:One of the goals of 2.x design is the absence of lost bugs. Sometimes the sequence ends or is canceled before the source callsonError
. In this case, the error has nowhere to go and it is sent toRxJavaPlugins.onError
2.0.6
, RxJavaPlugins.onError
tries to be smarter and shares the library / implementation errors and situations when the error cannot be delivered. Errors categorized as “bugs” are caused as they are, the rest are wrapped in UndeliverableException
and then called. All this logic can be seen here ( onError
and isBug
).RxJava
is OnErrorNotImplementedException
. This error occurs when the observable
causes an error, and the onError
method is not implemented in the subscriber. This error is an example of an error that for the basic error handler RxJava
is a “bug” and does not turn into a UndeliverableException
.RxJava
wraps in a UndeliverableException
are more interesting, since it may not always be obvious why an error cannot be delivered before onError
.UndeliverableException
is the 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() } )
onError
will be called twice, but this is contrary to the Reactive streams
specification .After a single call to a terminal event (onError
,onCompelete
), it is required that no calls be made again.
onError
call onError
second call is no longer possible. What happens when a second error occurs at the source? It will be delivered to RxJavaPlugins.onError
.zip
to join network calls (for example, two Retrofit
calls that return Observable
). If an error occurs in both calls (for example, there is no internet connection), both sources will cause errors, the first of which will go to the onError
implementation, and the second will be delivered to the basic error handler ( RxJavaPlugins.onError
).ConnectableObservable
can also cause UndeliverableException
. It is worth recalling that ConnectableObservable
raises events regardless of the presence of active subscribers, just call the connect()
method. If there are no errors in ConnectableObservable
if there are no subscribers, it will be delivered to the underlying error handler. someApi.retrofitCall() // Retrofit .publish() .connect()
someApi.retrofitCall()
causes an error (for example, there is no internet connection), the application will crash, since the network error will be delivered to the basic RxJava
error RxJava
.ConnectableObservable
is still connected, but it has no subscribers. I encountered this when using autoConnect()
when calling the API. autoConnect()
does not automatically disable Observable
. I unsubscribed in the onStop
method of the Activity
, but the result of the network call was returned after the destruction of the Activity
and the application UndeliverableException
with UndeliverableException
.RxJavaPlugins.onError
.zipWith
example is to take one or both sources and implement one of the methods for catching errors in them. For example, you can use onErrorReturn
to pass a default value instead of an error.ConnectableObservable
easier to fix - just make sure you disconnect the Observable
at the time when the last subscriber unsubscribes. autoConnect()
, for example, has an overloaded implementation that accepts a function that captures the connection point ( more can be found here ).RxJavaPlugins.setErrorHandler(Consumer<Throwable>)
method will help you with this. If this is a suitable solution for you, you can intercept all errors sent to RxJavaPlugins.onError
and process them as you see fit. This solution can be quite complicated - remember that RxJavaPlugins.onError
receives errors from all streams of RxJava
in the application.Observable
, you can call emitter.tryOnError()
instead of emitter.tryOnError()
. This method sends an error only if the stream (stream) is not destroyed (terminated) and has subscribers. Remember that this method is experimental.onError
in the subscribers. You should be aware of situations in which errors may be inaccessible to subscribers, and make sure that these situations are handled.Source: https://habr.com/ru/post/422611/
All Articles