使用RxJava2调用Retrofit2有时会抛出IOException(而不是调用onError处理程序)

时间:2017-04-24 19:55:26

标签: android retrofit2 okhttp3 rx-java2 okhttp

tl; dr:如何在使用RxJava2进行Retrofit2调用时捕获IOExceptions(和后代)?

讨论

我正在使用Retrofit2和RxJava2。我已经指定了一个onError处理程序。尽管如此,我的应用仍然会在IOException s时崩溃 - 特别是SocketTimeoutException。我在Github上提交了issue反对Retrofit,但我想知道我是在误用它还是遗漏了一些明显的东西。

以下是我创建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的所有后代似乎都绕过了这个并且崩溃了。

RxJava2CallAdapterFactory状态的javadoc:

  

响应包装体(例如,Observable)使用响应对象调用onNext以获取所有HTTP响应,并使用IOException调用onError以解决网络错误。

尽管如此,我看到这个堆栈跟踪崩溃:

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后,我没有再次发现问题。要么我很幸运,要么修好它。

作为最后一点,我还将我的Retrofit服务从返回Flowable<Response<Thing>>的实例更改为Flowable<Result<Thing>>,以直接引用该调用导致的任何Throwable。这可能有所帮助,也可能是多余的。

0 个答案:

没有答案