Подтвердить что ты не робот

RxJava: ошибка при попытке распространения ошибки в Observer.onError

Я получаю ошибку IllegalStateException в библиотеке Rx и не знаю точно, где корень проблемы, будь то с RxJava или что-то, что я могу делать неправильно.

Неудачный сбой происходит при прикреплении сертификата (происходит на всех запросах сервера), но, похоже, указывает на тайм-аут сеанса или выход из системы и обратно. Шаги Repro (около 25% времени) выглядят следующим образом: логин, открытый список item - прокрутить весь конец - выйти из системы - войти в систему - открыть приложение - закрыть приложение → Сбой!

У кого-нибудь есть идеи о том, как предотвратить это? Я нашел аналогичную проблему здесь Observer.onError, стреляющий непоследовательно

java.lang.IllegalStateException: Fatal Exception thrown on Scheduler.Worker thread.
   at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:62)
   at android.os.Handler.handleCallback(Handler.java:615)
   at android.os.Handler.dispatchMessage(Handler.java:92)
   at android.os.Looper.loop(Looper.java:137)
   at android.app.ActivityThread.main(ActivityThread.java:4867)
   at java.lang.reflect.Method.invokeNative(Method.java)
   at java.lang.reflect.Method.invoke(Method.java:511)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1007)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:774)
   at dalvik.system.NativeStart.main(NativeStart.java)
Caused by: rx.exceptions.OnErrorFailedException: Error occurred when trying to propagate error to Observer.onError
   at rx.observers.SafeSubscriber._onError(SafeSubscriber.java:201)
   at rx.observers.SafeSubscriber.onError(SafeSubscriber.java:111)
   at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber$2.call(OperatorObserveOn.java:159)
   at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
   at android.os.Handler.handleCallback(Handler.java:615)
   at android.os.Handler.dispatchMessage(Handler.java:92)
   at android.os.Looper.loop(Looper.java:137)
   at android.app.ActivityThread.main(ActivityThread.java:4867)
   at java.lang.reflect.Method.invokeNative(Method.java)
   at java.lang.reflect.Method.invoke(Method.java:511)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1007)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:774)
   at dalvik.system.NativeStart.main(NativeStart.java)
Caused by: rx.exceptions.CompositeException: 2 exceptions occurred. 
   at rx.observers.SafeSubscriber._onError(SafeSubscriber.java:201)
   at rx.observers.SafeSubscriber.onError(SafeSubscriber.java:111)
   at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber$2.call(OperatorObserveOn.java:159)
   at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
   at android.os.Handler.handleCallback(Handler.java:615)
   at android.os.Handler.dispatchMessage(Handler.java:92)
   at android.os.Looper.loop(Looper.java:137)
   at android.app.ActivityThread.main(ActivityThread.java:4867)
   at java.lang.reflect.Method.invokeNative(Method.java)
   at java.lang.reflect.Method.invoke(Method.java:511)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1007)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:774)
   at dalvik.system.NativeStart.main(NativeStart.java)
Caused by: rx.exceptions.CompositeException$CompositeExceptionCausalChain: Chain of Causes for CompositeException In Order Received =>
   at com.crashlytics.android.SessionDataWriter.getEventAppExecutionExceptionSize(SessionDataWriter.java:597)
   at com.crashlytics.android.SessionDataWriter.getEventAppExecutionExceptionSize(SessionDataWriter.java:600)
   at com.crashlytics.android.SessionDataWriter.getEventAppExecutionExceptionSize(SessionDataWriter.java:600)
   at com.crashlytics.android.SessionDataWriter.getEventAppExecutionSize(SessionDataWriter.java:533)
   at com.crashlytics.android.SessionDataWriter.getEventAppSize(SessionDataWriter.java:492)
   at com.crashlytics.android.CrashlyticsUncaughtExceptionHandler.writeSessionEvent(CrashlyticsUncaughtExceptionHandler.java:956)
   at com.crashlytics.android.CrashlyticsUncaughtExceptionHandler.access$200(CrashlyticsUncaughtExceptionHandler.java:56)
   at com.crashlytics.android.CrashlyticsUncaughtExceptionHandler$7.call(CrashlyticsUncaughtExceptionHandler.java:274)
   at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
   at java.util.concurrent.FutureTask.run(FutureTask.java:137)
   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
   at io.fabric.sdk.android.services.common.ExecutorUtils$1$1.onRun(ExecutorUtils.java:58)
   at io.fabric.sdk.android.services.common.BackgroundPriorityRunnable.run(BackgroundPriorityRunnable.java:13)
   at java.lang.Thread.run(Thread.java:856)
4b9b3361

Ответ 1

Что происходит в том, что ваша реализация onError в Subscriber бросает неконтролируемое исключение, которое противоречит контракту Observable, и это отменяет наблюдаемую обработку, бросающую OnErrorFailedException в планировщик observeOn.

Ответ 2

Вероятно, вы передаете контекст активности где-то из вашего обратного вызова onError. Это происходило со мной, когда я пытался показать AlertDialog - передав ему конкретный контекст активности - и нажав кнопку "Назад" до появления этого диалогового окна. Мой совет состоит в том, чтобы не передавать контексты активности таким образом.

Ответ 3

Вот как я решил проблему:

public abstract class MyNetworkSubscriber<T> extends Subscriber<T> {

@Override
public void onCompleted() {}

@Override
public void onError(Throwable e) {
    if (e instanceof HttpException) {
        ResponseBody responseBody = ((HttpException) e).response().errorBody();
        try {
            if (responseBody != null) {
                MyError error = new Gson().fromJson(responseBody.string(), MyError.class);
                onErrorCode(error);
            }
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    } else {
        e.printStackTrace();
    }
}

public void onErrorCode(MyError error){};
}

По какой-то причине OkHttp заставил меня поймать onError, чтобы я это сделал. Если я этого не сделаю, OkHttp/Retrofit выйдет из строя, и приложение отключится.

Предоставив это решение,

  • вы можете переопределить свой собственный onErrorCode и получить более подробный объект обратно как ошибку, которая исходит из вашего API, но вам этого не нужно.
  • OnError переопределяется, больше никаких сумасшедших сбоев.
  • И последнее, но не менее важное, по-прежнему является общим из-за <T>!

Вы также можете заставить overComplete и onError переопределяться, чтобы сделать абстрактные методы.

Ответ 4

если вы хотите обновить интерфейс в onError, просто попробуйте:

api.subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Subscriber(){....})