web-dev-qa-db-fra.com

RxJava: une erreur s'est produite lors de la tentative de propagation de l'erreur à Observer.onError

Je reçois une erreur IllegalStateException dans la bibliothèque Rx et je ne sais pas exactement où est la racine du problème, que ce soit avec RxJava ou quelque chose que je fais peut-être incorrectement.

Le crash fatal se produit lors de l'épinglage de certificat (se produit sur toutes les demandes de serveur) mais semble pointer vers un délai d'expiration ou une déconnexion de session et se reconnecter. tout le chemin - déconnexion - reconnexion - ouvrir l'application - fermer l'application -> Crash!

Quelqu'un a-t-il des idées sur la façon de prévenir cela? J'ai trouvé un problème similaire ici Observer.onError se déclenchant de manière incohérente

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)
37
Scott B

Ce qui se passe, c'est que votre implémentation onError dans un Subscriber lève une exception non vérifiée qui est contraire au contrat Observable et cela annule le traitement observable lançant un OnErrorFailedException dans le observeOn ordonnanceur.

46
Dave Moten

Vous passez probablement un contexte d'activité quelque part à partir de votre rappel onError. Cela m'arrivait lorsque j'essayais d'afficher un AlertDialog - en lui passant un contexte d'activité spécifique - et en appuyant sur le bouton de retour avant que cette boîte de dialogue n'apparaisse. Mon conseil est de ne pas passer les contextes d'activité de cette façon.

11
IgorGanapolsky

Voici comment j'ai résolu le problème:

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){};
}

Pour une raison quelconque, OkHttp me forçait à attraper onError donc je l'ai fait. Si je ne le fais pas, OkHttp/Retrofit plantera et l'application s'arrêtera.

En fournissant cette solution,

  1. vous pouvez choisir de remplacer votre propre onErrorCode et récupérer un objet plus détaillé en tant qu'erreur provenant de votre API, mais ce n'est pas obligatoire.
  2. OnError est surchargé, plus de crash fou.
  3. Et enfin et surtout, il est toujours générique à cause de <T>!

Vous pouvez également forcer onComplete & onError à être remplacé pour rendre les méthodes abstraites.

1
Karl-John Chow