2017-03-09 28 views
3

以下代碼表示下載文件。當Observable被處置時,該呼叫將被取消。在我的情況下,Observable將被放置在Fragment的onDestroy()方法中(由於事實上它不需要繼續下載已被或將被銷燬的片段上的文件)。每當在文件的下載過程中發生場景取消時,此代碼將以SocketException崩潰。該消息可以是「套接字關閉」或「非套接字上的套接字操作」。我的問題是如何使用OkHttp正確取消正在進行的下載請求?使用OkHttp取消呼叫時的SocketException

代碼:

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) 
+0

顯示的代碼與rx-java或rx-android沒有任何關係。 –

+0

你可以附上Util.closeQuietly()方法的代碼嗎? – yosriz

+0

這是按設計工作。當你取消一個調用時,它的流會拋出異常。 –

回答

0

在代碼

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

您發送onError()到發射器是誰已經退訂,而你片段銷燬。 請檢查:

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