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.RxJavaRxJava , 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