在OkHttp取消调用回调失败 [英] Callback failure for canceled call in OkHttp

查看:3475
本文介绍了在OkHttp取消调用回调失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在取消排队OkHttp电话(版本2.4)客户端有时会抛出回调失败已取消呼叫到http:// ... 既不回调方法被执行。

由于我必须提供或正或负反馈给用户,已经回调吃掉一样,是不能接受的。我怎样才能解决这个错误得到什么?

我已创建了两个按钮(一个用于开始下载请求时,另一个用于消除的话),文本视图和图像视图测试应用程序,显示错误的大部分时间。在取消按钮,但使用原来我已经赶上错误点击与处理程序自动点击是成功地重复错误更有效。

 包com.test.httptest;进口android.app.Activity;
进口android.graphics.Bitmap;
进口android.graphics.BitmapFactory;
进口android.os.Bundle;
进口android.os.Handler;
进口android.view.View;
进口android.widget.ImageView;
进口android.widget.TextView;进口com.squareup.okhttp.Call;
进口com.squareup.okhttp.Callback;
进口com.squareup.okhttp.OkHttpClient;
进口com.squareup.okhttp.Request;
进口com.squareup.okhttp.Response;进口java.io.IOException异常;公共类MainActivity扩展活动
{
    最后的私人OkHttpClient客户端=新OkHttpClient();
    私有对象取消=新的对象();    @覆盖
    保护无效的onCreate(捆绑savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        的setContentView(R.layout.activity_main);
    }    公共无效onHttpClick(视图V)
    {
        TextView的电视=(的TextView)findViewById(R.id.text_view);
        tv.setText(开始);
        downloadImage(http://httpbin.org/image/jpeg);
        //模拟点击取消
        新的处理程序()。postDelayed(新的Runnable()
        {
            公共无效的run()
            {
                onCancelClick(NULL);
            }
        },380);
    }    公共无效onCancelClick(视图V)
    {
        TextView的电视=(的TextView)findViewById(R.id.text_view);
        tv.setText(取消);
        client.cancel(取消);
    }    公共无效downloadImage(字符串URL)
    {
        请求请求=新Request.Builder()
                .TAG(取消)
                的.url(URL)
                。建立();        致电致电= client.newCall(请求);
        call.enqueue(新回拨()
        {
            字符串结果=;            @覆盖
            公共无效onFailure处(请求的要求,IOException异常E)
            {
                结果= e.getMessage();
                runOnUiThread(新的Runnable()
                {
                    @覆盖
                    公共无效的run()
                    {
                        TextView的电视=(的TextView)findViewById(R.id.text_view);
                        tv.setText(结果);
                    }
                });
            }            @覆盖
            公共无效onResponse(响应响应)抛出IOException异常
            {
                如果(response.isSuccessful())
                {
                    。最后一个字节[] =输入response.body()个字节();
                    最终诠释LEN =(int)的response.body()CONTENTLENGTH();                    runOnUiThread(新的Runnable()
                    {
                        @覆盖
                        公共无效的run()
                        {
                            TextView的电视=(的TextView)findViewById(R.id.text_view);
                            tv.setText(完成);
                            ImageView的IV =(ImageView的)findViewById(R.id.image_view);
                            位图BM = BitmapFactory.de codeByteArray的(输入,0,LEN);
                            iv.setImageBitmap(BM);
                        }
                    });
                }
                其他
                {
                    。结果= response.body()字符串();
                    runOnUiThread(新的Runnable()
                    {
                        @覆盖
                        公共无效的run()
                        {
                            TextView的电视=(的TextView)findViewById(R.id.text_view);
                            tv.setText(结果);
                        }
                    });
                }            }        });
    }
}

logcat的:

  08-24 23:00:13.151 14403-14451 / com.test.httptest I / OkHttpClient:回调失败已取消呼叫到http://httpbin.org / ...
    产生java.net.SocketException:套接字关闭
            在libcore.io.Posix.recvfromBytes(本机方法)
            在libcore.io.Posix.recvfrom(Posix.java:141)
            在libcore.io.BlockGuardOs.recvfrom(BlockGuardOs.java:164)
            在libcore.io.IoBridge.recvfrom(IoBridge.java:506)
            在java.net.PlainSocketImpl.read(PlainSocketImpl.java:488)
            在java.net.PlainSocketImpl.access $ 000(PlainSocketImpl.java:46)
            在java.net.PlainSocketImpl $ PlainSocketInputStream.read(PlainSocketImpl.java:240)
            在okio.Okio $ 2.read(Okio.java:137)
            在okio.AsyncTimeout $ 2.read(AsyncTimeout.java:211)
            在okio.RealBufferedSource.read(RealBufferedSource.java:50)
            在com.squareup.okhttp.internal.http.HttpConnection $ FixedLengthSource.read(HttpConnection.java:418)
            在okio.Buffer.writeAll(Buffer.java:956)
            在okio.RealBufferedSource.readByteArray(RealBufferedSource.java:92)
            在com.squareup.okhttp.ResponseBody.bytes(ResponseBody.java:57)
            在hr.artplus.httptestm.MainActivity $ 2.onResponse(MainActivity.java:87)
            在com.squareup.okhttp.Call $ AsyncCall.execute(Call.java:170)
            在com.squareup.okhttp.internal.NamedRunnable.run(NamedRunnable.java:33)
            在java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
            在java.util.concurrent.ThreadPoolExecutor中的$ Worker.run(ThreadPoolExecutor.java:587)
            在java.lang.Thread.run(Thread.java:841)


解决方案

它的的呼唤你的 onResponse 方法。它出现在堆栈跟踪

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

正在发生的事情是,你得到一个 IOException异常在这条线 -

 最后一个字节[] =输入response.body()个字节()。

大概是因为当你读它由于取消流被关闭。您code允许例外传播备份到回调类,它不会发出另一个回调,因为它已经被称为 onResponse

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

 如果(response.isSuccessful()){
   尝试{
       。最后一个字节[] =输入response.body()个字节();
       最终诠释LEN =(int)的response.body()CONTENTLENGTH();
   }赶上(IOException异常五){
       //信号给用户故障在这里,重新抛出异常,或
       //其他任何你想在做失败
   }
   ...

Canceling enqueued calls in OkHttp (version 2.4) client sometimes throws Callback failure for canceled call to http://... and neither of callback methods gets executed.

Since I have to provide either positive or negative feedback to the user, having callback eaten up like that is not acceptable. How can I get around that error?

I have created test application with two buttons (one for starting download request, another for canceling it), text view and image view, that shows error most of the time. Originally, I have caught error clicking on Cancel button, but using auto-click with handler is much more effective for repeating the error successfully.

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)

解决方案

It is calling your onResponse method. It appears in the stack trace as

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

What is happening is that the you are getting an IOException on this line --

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

probably because the stream is closed while you were reading it due to the cancellation. Your code lets the exception propagate back up to the Callback class, which does not issue another callback because it already called onResponse.

You can catch the exception and deal with it in your callback --

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
   }
   ...                    

这篇关于在OkHttp取消调用回调失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆