android - Retrofit/OkHTTP/RxJava 间歇性 InterruptedIOException

标签 android retrofit rx-java okhttp rx-android

我正在使用以下(过时的)库:

Retrofit: 1.9.0
OkHTTP: 2.3.0
RxAndroid: 0.24.0

我注意到,每隔一段时间我就会收到以下 POST 请求的堆栈跟踪:

 D/Retrofit: ---> HTTP POST https:xxxxx
 D/Retrofit: Content-Type: application/x-www-form-urlencoded; charset=UTF-8
 D/Retrofit: Content-Length: 396
 D/Retrofit: ---> END HTTP (396-byte body)
 D/Retrofit: ---- ERROR https:xxxxx
 I/Choreographer: Skipped 33 frames!  The application may be doing too much work on its main thread.
 D/Retrofit: java.io.InterruptedIOException
   at okio.Timeout.throwIfReached(Timeout.java:146)
   at okio.Okio$1.write(Okio.java:75)
   at okio.AsyncTimeout$1.write(AsyncTimeout.java:155)
   at okio.RealBufferedSink.flush(RealBufferedSink.java:201)
   at com.squareup.okhttp.internal.http.HttpConnection.flush(HttpConnection.java:140)
   at com.squareup.okhttp.Connection.makeTunnel(Connection.java:399)
   at com.squareup.okhttp.Connection.upgradeToTls(Connection.java:229)
   at com.squareup.okhttp.Connection.connect(Connection.java:159)
   at com.squareup.okhttp.Connection.connectAndSetOwner(Connection.java:175)
   at com.squareup.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:120)
   at com.squareup.okhttp.internal.http.HttpEngine.nextConnection(HttpEngine.java:330)
   at com.squareup.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:319)
   at com.squareup.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:241)
   at com.squareup.okhttp.Call.getResponse(Call.java:271)
   at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:228)
   at com.squareup.okhttp.Call.getResponseWithInterceptorChain(Call.java:199)
   at com.squareup.okhttp.Call.execute(Call.java:79)
   at retrofit.client.OkClient.execute(OkClient.java:53)
   at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:326)
   at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:240)
   at java.lang.reflect.Proxy.invoke(Proxy.java:913)
   at $Proxy1.replyTransaction(Unknown Source)
   < App Specific Trace > 
   at rx.Observable$1.call(Observable.java:145)
   at rx.Observable$1.call(Observable.java:137)
   at rx.Observable.unsafeSubscribe(Observable.java:7304)
   at rx.internal.operators.OperatorSubscribeOn$1$1.call(OperatorSubscribeOn.java:62)
   at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:47)
   at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:457)
   at java.util.concurrent.FutureTask.run(FutureTask.java:266)
   at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
   at java.lang.Thread.run(Thread.java:764)
 D/Retrofit: ---- END ERROR
 retrofit.RetrofitError
     at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:395)
     at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:240)
     at java.lang.reflect.Proxy.invoke(Proxy.java:913)
     at $Proxy1.replyTransaction(Unknown Source)
     < App Specific Trace > 
     at rx.Observable$1.call(Observable.java:145)
     at rx.Observable$1.call(Observable.java:137)
     at rx.Observable.unsafeSubscribe(Observable.java:7304)
     at rx.internal.operators.OperatorSubscribeOn$1$1.call(OperatorSubscribeOn.java:62)
     at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:47)
     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:457)
     at java.util.concurrent.FutureTask.run(FutureTask.java:266)
     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
     at java.lang.Thread.run(Thread.java:764)
  Caused by: java.io.InterruptedIOException
     at okio.Timeout.throwIfReached(Timeout.java:146)
     at okio.Okio$1.write(Okio.java:75)
     at okio.AsyncTimeout$1.write(AsyncTimeout.java:155)
     at okio.RealBufferedSink.flush(RealBufferedSink.java:201)
     at com.squareup.okhttp.internal.http.HttpConnection.flush(HttpConnection.java:140)
     at com.squareup.okhttp.Connection.makeTunnel(Connection.java:399)
     at com.squareup.okhttp.Connection.upgradeToTls(Connection.java:229)
     at com.squareup.okhttp.Connection.connect(Connection.java:159)
     at com.squareup.okhttp.Connection.connectAndSetOwner(Connection.java:175)
     at com.squareup.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:120)
     at com.squareup.okhttp.internal.http.HttpEngine.nextConnection(HttpEngine.java:330)
     at com.squareup.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:319)
     at com.squareup.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:241)
     at com.squareup.okhttp.Call.getResponse(Call.java:271)
     at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:228)
     at com.squareup.okhttp.Call.getResponseWithInterceptorChain(Call.java:199)
     at com.squareup.okhttp.Call.execute(Call.java:79)
     at retrofit.client.OkClient.execute(OkClient.java:53)
     at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:326)
     at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:240) 
     at java.lang.reflect.Proxy.invoke(Proxy.java:913) 
     at $Proxy1.replyTransaction(Unknown Source) 
     < App Specific Trace > 
     at rx.Observable$1.call(Observable.java:145) 
     at rx.Observable$1.call(Observable.java:137) 
     at rx.Observable.unsafeSubscribe(Observable.java:7304) 
     at rx.internal.operators.OperatorSubscribeOn$1$1.call(OperatorSubscribeOn.java:62) 
     at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:47) 
     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:457) 
     at java.util.concurrent.FutureTask.run(FutureTask.java:266) 
     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301) 
     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) 
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) 
     at java.lang.Thread.run(Thread.java:764)

我的代码如下:

网络调用:

    return Observable.create(new Observable.OnSubscribe<Object>() {
      @Override public void call(Subscriber<? super Object> subscriber) {
        try {
          subscriber.onNext(/* Sync network call here. */);
        } catch (Exception e) {
          subscriber.onError(e);
        }
        subscriber.onCompleted();
      }
    })
        .onBackpressureBuffer()
        // singleton for Schedulers.io()
        .subscribeOn(ioScheduler)
        // singleton for AndroidSchedulers.mainThread()
        .observeOn(mainThreadScheduler);

其名称如下:

subscription = makeNetworkCall()
            .subscribe(new Observer<Object>() {
              @Override public void onNext(Object object) {
                // close and finish activity
              }
              @Override public void onError(Throwable e) {
                // whoops!
              }
            });

并在 Activity 中取消订阅,如下所示:

  @Override
  protected void onPause() {
    super.onPause();
    if (subscription != null) {
      subscription.unsubscribe();
      subscription = null;
      if (condition) {
        finish();
      }
    }
  }

我对此的理解是,我收到 InterruptedException 因为我在 onPause 中从 Subscriptionunsubscribe() ()。不过,我们会针对其他请求执行此操作,因此我不确定为什么我只在这里看到它以及到底为什么会发生这种情况。

为了提供更多相关信息,网络调用是通过通知操作从锁定屏幕启动的 Activity 进行的,以强制用户解锁其设备以便采取操作。

我的问题是为什么会发生这种情况,有没有好的方法可以解决这个问题?根据一些文章,您应该在 onPause() 取消订阅 Observables

更多信息可以参见 In okHTTP's github issues

谢谢!

最佳答案

这是一个猜测,但可能是您在发出中断异常之前没有检查订阅者是否仍然存在。

试试这个:

return Observable.create(new Observable.OnSubscribe<Object>() {
      @Override public void call(Subscriber<? super Object> subscriber) {
        try {
          subscriber.onNext(/* Sync network call here. */);
          subscriber.onCompleted();
        } catch (Exception e) {
          if (!subscriber.isUnsubscribed()) { // <-- check before emitting error
            subscriber.onError(e);
          }
        }
      }
    })

关于android - Retrofit/OkHTTP/RxJava 间歇性 InterruptedIOException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48068595/

相关文章:

Android StrictMode 报告误报

android - 内容在 Android fragment 中不可见

java - Flow API 中的 subscription.request(n) 如何在任意 n 值执行背压?

java - 在 Web 应用程序中使用 RxJava Observables 无法解释的缺乏性能改进

java - 使用Android AFreeChart将折线图保存为png或jpeg文件

安卓多任务处理

android - 使用 Picasso 强制重新下载图像

java - 在改造中处理超过 1 个响应

android - 改造转换器工厂无法访问 GsonConverterFactory

android - 可以发布主题有多个订阅者