網路請求異常導致app奔潰Caused by: rx.exceptions.OnErrorFailedException
一,問題描述:專案中使用的是Rxjava1.x+和retrofit2.x+搭建的網路請求框架。向後端請求資料時,由於伺服器未開啟,出現伺服器連線異常,這是控制檯輸出的異常日誌。這個時候rxjava會呼叫onError(Throwable e)方法,這樣我們就可以根據異常型別來顯示一個異常頁面來給使用者一個友好的提醒。但我在除錯過程中App卻崩潰了,crash日誌如下
java.lang.IllegalStateException: Fatal Exception thrown on Scheduler.Worker thread. at rx.android.schedulers.LooperScheduler$ScheduledAction.run(LooperScheduler.java:114) at android.os.Handler.handleCallback(Handler.java:742) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:157) at android.app.ActivityThread.main(ActivityThread.java:5571) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:745) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:635) Caused by: rx.exceptions.OnErrorFailedException: Error occurred when trying to propagate error to Observer.onError at rx.observers.SafeSubscriber._onError(SafeSubscriber.java:187) at rx.observers.SafeSubscriber.onError(SafeSubscriber.java:115) at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.checkTerminated(OperatorObserveOn.java:273) at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.call(OperatorObserveOn.java:216) at rx.android.schedulers.LooperScheduler$ScheduledAction.run(LooperScheduler.java:107) at android.os.Handler.handleCallback(Handler.java:742) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:157) at android.app.ActivityThread.main(ActivityThread.java:5571) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:745) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:635) Caused by: rx.exceptions.CompositeException: 2 exceptions occurred. at rx.observers.SafeSubscriber._onError(SafeSubscriber.java:187) at rx.observers.SafeSubscriber.onError(SafeSubscriber.java:115) at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.checkTerminated(OperatorObserveOn.java:273) at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.call(OperatorObserveOn.java:216) at rx.android.schedulers.LooperScheduler$ScheduledAction.run(LooperScheduler.java:107) at android.os.Handler.handleCallback(Handler.java:742) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:157) at android.app.ActivityThread.main(ActivityThread.java:5571) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:745) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:635) Caused by: rx.exceptions.CompositeException$CompositeExceptionCausalChain: Chain of Causes for CompositeException In Order Received => at android.util.Log.getStackTraceString(Log.java:342) at com.android.internal.os.RuntimeInit.Clog_e(RuntimeInit.java:114) at com.android.internal.os.RuntimeInit.access$200(RuntimeInit.java:50) at com.android.internal.os.RuntimeInit$UncaughtHandler.uncaughtException(RuntimeInit.java:161) at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:693) at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:690) at rx.android.schedulers.LooperScheduler$ScheduledAction.run(LooperScheduler.java:118) at android.os.Handler.handleCallback(Handler.java:742) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:157) at android.app.ActivityThread.main(ActivityThread.java:5571) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:745) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:635) Caused by: java.net.ConnectException: Failed to connect to /192.168.x.xxx:8888 at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.java:240) at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:158) at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:256) at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:134) at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:113) at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121) at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121) at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:125) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121) at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:212) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
可以看到crash主要是由下面的異常導致
Caused by: rx.exceptions.OnErrorFailedException
Caused by: rx.exceptions.CompositeException
rx原始碼裡面對OnErrorFailedException的描述是
Represents an exception used to re-throw errors thrown from {@link Subscriber#onError(Throwable)}.
意思大概是用於在Subscriber的onError(Throwable)方法中丟擲錯誤,就是說在Subscriber的onError(Throwable)方法中產生了新的異常,這個異常會被Rxjava丟擲;
這樣就明瞭了,檢查一下onError(Throwable)中的程式碼,看看有沒有有錯誤。果然,在onError(Throwable)方法中我判斷了當前的網狀態,而沒有申請訪問網路狀態的許可權,從而產生異常;在清單檔案申請訪問網路狀態許可權後,就沒有問題了。
二,學習一下CompositeException
原始碼中的描述:Represents an exception that is a composite of one or more other exceptions. A {@code CompositeException} does not modify the structure of any exception it wraps, but at print-time it iterates through the list of Throwables contained in the composite in order to print them all.
意思是,表示由一個或多個其他異常組合而成的異常。{@code CompositeException}不會修改它所包裝的任何異常的結構,但在列印時,它會遍歷組合中包含的可拋棄項列表,以便將它們全部打印出來。
檢視上面的錯誤日誌,有這麼一行
Caused by: rx.exceptions.CompositeException: 2 exceptions occurred.
他說明了CompositeException包含了兩個異常並且分別輸出在控制檯中(不知道這麼理解對不對)
其一是rx.exceptions.CompositeException$CompositeExceptionCausalChain
其二是java.net.ConnectException
這裡CompositeExceptionCausalChain是CompositeException的靜態內部類繼承自RuntimeException
三,總結
使用rxjava1.x+出現異常OnErrorFailedException要留心onError(Throwable)中的程式碼是否正確