【问题标题】:Callback failure for canceled call in OkHttpOkHttp 中取消调用的回调失败
【发布时间】:2015-08-24 21:16:19
【问题描述】:

取消 OkHttp(2.4 版)客户端中的排队调用有时会抛出 Callback failure for canceled call to http://... 并且两个回调方法都不会执行。

由于我必须向用户提供正面或负面的反馈,因此无法接受这样的回调。我怎样才能绕过这个错误?

我创建了带有两个按钮的测试应用程序(一个用于开始下载请求,另一个用于取消下载请求),文本视图和图像视图,大多数情况下都会显示错误。最初,我在单击取消按钮时遇到了错误,但使用带有处理程序的自动单击对于成功重复错误更有效。

package com.test.httptest;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import com.squareup.okhttp.Call;
import com.squareup.okhttp.Callback;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;

import java.io.IOException;

public class MainActivity extends Activity
{
    final private OkHttpClient client = new OkHttpClient();
    private Object cancel = new Object();

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void onHttpClick(View v)
    {
        TextView tv = (TextView) findViewById(R.id.text_view);
        tv.setText("start");
        downloadImage("http://httpbin.org/image/jpeg");
        // simulate cancel click
        new Handler().postDelayed(new Runnable()
        {
            public void run()
            {
                onCancelClick(null);
            }
        }, 380);
    }

    public void onCancelClick(View v)
    {
        TextView tv = (TextView) findViewById(R.id.text_view);
        tv.setText("canceling");
        client.cancel(cancel);
    }

    public void downloadImage(String url)
    {
        Request request = new Request.Builder()
                .tag(cancel)
                .url(url)
                .build();

        Call call = client.newCall(request);
        call.enqueue(new Callback()
        {
            String result = "";

            @Override
            public void onFailure(Request request, IOException e)
            {
                result = e.getMessage();
                runOnUiThread(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        TextView tv = (TextView) findViewById(R.id.text_view);
                        tv.setText(result);
                    }
                });
            }

            @Override
            public void onResponse(Response response) throws IOException
            {
                if (response.isSuccessful())
                {
                    final byte[] input = response.body().bytes();
                    final int len = (int) response.body().contentLength();

                    runOnUiThread(new Runnable()
                    {
                        @Override
                        public void run()
                        {
                            TextView tv = (TextView) findViewById(R.id.text_view);
                            tv.setText("completed");
                            ImageView iv = (ImageView) findViewById(R.id.image_view);
                            Bitmap bm = BitmapFactory.decodeByteArray(input, 0, len);
                            iv.setImageBitmap(bm);
                        }
                    });
                }
                else
                {
                    result = response.body().string();
                    runOnUiThread(new Runnable()
                    {
                        @Override
                        public void run()
                        {
                            TextView tv = (TextView) findViewById(R.id.text_view);
                            tv.setText(result);
                        }
                    });
                }

            }

        });
    }
}

Logcat:

08-24 23:00:13.151  14403-14451/com.test.httptest I/OkHttpClient﹕ Callback failure for canceled call to http://httpbin.org/...
    java.net.SocketException: Socket closed
            at libcore.io.Posix.recvfromBytes(Native Method)
            at libcore.io.Posix.recvfrom(Posix.java:141)
            at libcore.io.BlockGuardOs.recvfrom(BlockGuardOs.java:164)
            at libcore.io.IoBridge.recvfrom(IoBridge.java:506)
            at java.net.PlainSocketImpl.read(PlainSocketImpl.java:488)
            at java.net.PlainSocketImpl.access$000(PlainSocketImpl.java:46)
            at java.net.PlainSocketImpl$PlainSocketInputStream.read(PlainSocketImpl.java:240)
            at okio.Okio$2.read(Okio.java:137)
            at okio.AsyncTimeout$2.read(AsyncTimeout.java:211)
            at okio.RealBufferedSource.read(RealBufferedSource.java:50)
            at com.squareup.okhttp.internal.http.HttpConnection$FixedLengthSource.read(HttpConnection.java:418)
            at okio.Buffer.writeAll(Buffer.java:956)
            at okio.RealBufferedSource.readByteArray(RealBufferedSource.java:92)
            at com.squareup.okhttp.ResponseBody.bytes(ResponseBody.java:57)
            at hr.artplus.httptestm.MainActivity$2.onResponse(MainActivity.java:87)
            at com.squareup.okhttp.Call$AsyncCall.execute(Call.java:170)
            at com.squareup.okhttp.internal.NamedRunnable.run(NamedRunnable.java:33)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
            at java.lang.Thread.run(Thread.java:841)

【问题讨论】:

    标签: java android okhttp


    【解决方案1】:

    正在调用你的onResponse 方法。它在堆栈跟踪中显示为

     at hr.artplus.httptestm.MainActivity$2.onResponse(MainActivity.java:87) 
    

    发生的事情是你在这条线上得到了一个IOException --

     final byte[] input = response.body().bytes();
    

    可能是因为在您阅读它时,由于取消,该流已关闭。您的代码允许异常传播回Callback 类,该类不会发出另一个回调,因为它已经调用了onResponse

    您可以在回调中捕获异常并处理它 --

    if (response.isSuccessful()) {
       try { 
           final byte[] input = response.body().bytes();
           final int len = (int) response.body().contentLength();
       } catch (IOException e) {
           // Signal to the user failure here, re-throw the exception, or 
           // whatever else you want to do on failure
       }
       ...                    
    

    【讨论】:

    • 就是这样,谢谢。看来我需要提高我的 Java 调试技能。由于错误的性质,我假设执行从未到达任何回调方法,并且我错过了 logcat 中的 onResponse 条目。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多