java - 使用 OkHttp 取消调用时出现 SocketException

标签 java android okhttp

下面的代码代表下载一个文件。当 Observable 被释放时,调用将被取消。在我的例子中,Observable 将在 Fragment 的 onDestroy() 方法中处理(因为它不需要继续下载文件到正在或将要被销毁的 Fragment 上)。每当在文件下载过程中发生取消场景时,此代码将崩溃并抛出 SocketException。该消息可以是“套接字已关闭”或“非套接字上的套接字操作”。我的问题是如何使用 OkHttp 正确取消正在进行的下载请求?

代码:

Request request = //..
final Call call = client.newCall(request);

   call.enqueue(new Callback() {

       @Override
       public void onFailure(Call call, IOException error)
       {
          Log.e("Acme", "OnFailure:", error);
          emitter.onError(error);
       }

       @Override
       public void onResponse(Call call, Response response) throws IOException
       {
           if (response.isSuccessful())
           {
               BufferedSink sink = null;
               BufferedSource source = null;
               try
               {
                   Log.d("Acme", "onResponse: Start writing..");
                   sink = Okio.buffer(Okio.sink(file));
                   source = response.body().source();
                   sink.writeAll(source); // Crash on this line.
                   sink.flush();

                   emitter.onNext(file);
                   emitter.onComplete();
               }
               catch (IOException exception)
               {
                   Log.e("Acme", "onResponse: Exception writing file:", exception);
                   emitter.onError(exception);
               }
               finally
               {
                   Log.d("Acme", "onResponse: Trying to close..");
                   Util.closeQuietly(sink);
                   Util.closeQuietly(source);
                   Log.d("Acme", "onResponse: Closed..");
               }
           }
       }
   });

   emitter.setCancellable(new Cancellable() {

       @Override
       public void cancel() throws Exception 
       {
           if (!call.isCanceled()) 
           {
               call.cancel();
           }
       }
   });
}

控制台:

D/Acme: onResponse: Start writing..
E/AndroidRuntime: FATAL EXCEPTION: OkHttp https://acme.nl/...
Process: nl.acme.app.development.debug, PID: 12432
java.net.SocketException: Socket operation on non-socket
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.read(SocketInputStream.java:151)
    at java.net.SocketInputStream.read(SocketInputStream.java:120)
    at okio.Okio$2.read(Okio.java:138)
    at okio.AsyncTimeout$2.read(AsyncTimeout.java:236)
    at okio.RealBufferedSource.read(RealBufferedSource.java:45)
    at okhttp3.internal.http1.Http1Codec$FixedLengthSource.read(Http1Codec.java:385)
    at okio.RealBufferedSource.read(RealBufferedSource.java:45)
    at okio.RealBufferedSink.writeAll(RealBufferedSink.java:97)
    at nl.app.acme.infrastructure.network.Api$44$1.onResponse(Api.java:3322)
    at okhttp3.RealCall$AsyncCall.execute(RealCall.java:135)
    at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
    at java.lang.Thread.run(Thread.java:761)

最佳答案

在代码中

catch (IOException exception)
{
    Log.e("Acme", "onResponse: Exception writing file:", exception);
    emitter.onError(exception);
}

您正在将 onError() 发送给在您销毁 fragment 时已经取消订阅的发射器。 请检查:

if (!emitter.isDisposed()) emitter.onError(exception);

关于java - 使用 OkHttp 取消调用时出现 SocketException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42696720/

相关文章:

java - 是否有一种与数据库无关的方法来确定 JDBC 中常见的 SQL 错误?

android nfc 阅读驾驶执照 BAC 与 BAP

android - 从 android/linux 中的特定 PID 获取所有日志?

Android OKHttp 和 Retrofit 返回 304 错误

java - 来自 Java 应用程序的 Apache cTAKES 逻辑

java - 在 Java 中将变量范围扩展到大括号之外

java - 为什么 listFiles() 在不同平台上表现不同?

android - onActivityCreated 方法在一个 fragment 中调用,但不在其他 fragment 中调用

java - okHttp 3.x 身份 validator 未被调用

java - OkHttp 客户端身份验证无法验证服务器并在同一请求中发送客户端证书