Вызов Retrofit2 с RxJava2 иногда вызывает IOException (вместо вызова обработчика onError)

tl;dr: Как мне перехватить IOExceptions (и потомков) при выполнении вызовов Retrofit2 с использованием RxJava2?

обсуждение

Я использую Retrofit2 с RxJava2. Я назначил обработчик onError. Тем не менее, мое приложение по-прежнему иногда зависает с IOException с - в частности, SocketTimeoutException, Я подал жалобу на Retrofit на Github, но мне интересно, не использую ли я ее или упускаю что-то очевидное.

Вот как я создаю свои сервисы Retrofit:

OkHttpClient.Builder okClient = new OkHttpClient.Builder()
        .addInterceptor(/* a variety of interceptors */)
        .connectTimeout(10, SECONDS)
        .writeTimeout(10, SECONDS)
        .readTimeout(30, SECONDS) // first attempt to head off timeout exception
        .build();

RxJava2CallAdapterFactory rxAdapter = 
RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io());
Factory gsonFactory = GsonAdapterFactory.gsonConverterFactory();
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(endpoint)
        .client(okClient)
        .addCallAdapterFactory(rxAdapter)
        .addConverterFactory(gsonFactory)
        .build();

return retrofit.create(Thing.class);

Пример определения модификации:

@GET("/thing")
Flowable<Response<Thing>> getThing();

Пример вызова с модифицированной услугой:

service.getThing()
    .map(response -> thingFromResponse(thing)) // here I check for a successful response
    .subscribe(thing -> doStuffWithThing(thing), // Consumer<Thing> onNext
               throwable -> handleError("Error getting thing", throwable) // Consumer<Throwable> onError
    );

Я ожидаю, что мой handleError() функция для обработки всех ошибок, но вместо этого все потомки IOException, кажется, обходят это и вместо этого дают сбой.

Javadoc для RxJava2CallAdapterFactory состояния:

Обернутое в ответ тело (например, Observable) вызывает onNext с объектом Response для всех HTTP-ответов и вызывает onError с IOException для сетевых ошибок.

Тем не менее, я вижу сбои с этой трассировкой стека:

Fatal Exception: java.net.SocketTimeoutException: timeout
       at okhttp3.internal.http2.Http2Stream$StreamTimeout.newTimeoutException(Http2Stream.java:593)
       at okhttp3.internal.http2.Http2Stream$StreamTimeout.exitAndThrowIfTimedOut(Http2Stream.java:601)
       at okhttp3.internal.http2.Http2Stream.takeResponseHeaders(Http2Stream.java:146)
       at okhttp3.internal.http2.Http2Codec.readResponseHeaders(Http2Codec.java:120)
       at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:67)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
       at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:45)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
       at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
       at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
       at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
       at com.myapp.backend.retrofit.interceptors.SigningInterceptor.intercept(SigningInterceptor.java:32)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
       at com.myapp.backend.retrofit.interceptors.UserTokenInterceptor.intercept(UserTokenInterceptor.java:28)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
       at com.myapp.backend.retrofit.interceptors.UserAgentHeaderInterceptor.intercept(UserAgentHeaderInterceptor.java:24)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
       at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:212)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
       at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:179)
       at okhttp3.RealCall.execute(RealCall.java:63)
       at retrofit2.OkHttpCall.execute(OkHttpCall.java:174)
       at com.jakewharton.retrofit2.adapter.rxjava2.CallObservable.subscribeActual(CallObservable.java:41)
       at io.reactivex.Observable.subscribe(Observable.java:10514)
       at io.reactivex.internal.operators.observable.ObservableSubscribeOn$1.run(ObservableSubscribeOn.java:39)
       at io.reactivex.Scheduler$1.run(Scheduler.java:134)
       at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:59)
       at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:51)
       at java.util.concurrent.FutureTask.run(FutureTask.java:237)
       at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:154)
       at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:269)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
       at java.lang.Thread.run(Thread.java:818)

РЕДАКТИРОВАТЬ:

После обновления адаптера rxjava2 с 1.1.0 (с com.jakewharton пакет) до 2.2.0, я больше не наблюдал проблемы. Либо мне повезло, либо это исправило.

В заключение, я также изменил свои услуги по модернизации с возврата экземпляров Flowable<Response<Thing>> в Flowable<Result<Thing>> чтобы получить прямую ссылку на любой Throwable S вызвано вызовом. Это могло бы помочь или было излишним.

0 ответов

Другие вопросы по тегам