如何使用OkHttp Android取消请求

时间:2017-09-28 13:20:46

标签: java android okhttp3

我读了帖子OkHttpClient cannot cancel Call by tag,但它不适合我。我有EditText TextWatcher来使用Google PlacesAutocomplete获取地点地址,因此每个输入的字符都是新请求,但我键入的每个字符都需要取消之前的请求,因此我无法收到它的回归,最重要的是最终的地址类型,我这样做了:

  

更新!

Address.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            if(Address.getText().toString().length() > 3){
                _Address = Address.getText().toString();
                if(call != null){
                    call.cancel();
                }

                Request request = new Request.Builder()
                        .url(getPlaceAutoCompleteUrl(_Address))
                        .addHeader("content-type", "application/json")
                        .addHeader("User-Agent", "Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; google_sdk Build/MR1) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30")
                        .build();
                Call call = new OkHttpClient().newCall(request);
                call.enqueue(new Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {

                    }
                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        Log.d("Response",response.body().string());
                        PlacePredictions place = LoganSquare.parse(response.body().string(),PlacePredictions.class);
                        if(autoCompleteAdapter == null){
                            autoCompleteAdapter = new AutoCompleteAdapter(CustomPlaces.this);
                            recyclerView.setAdapter(autoCompleteAdapter);
                            autoCompleteAdapter.Add(place.getPlaces());
                        }else {
                            autoCompleteAdapter.Clear();
                            autoCompleteAdapter.Add(place.getPlaces());
                            autoCompleteAdapter.notifyDataSetChanged();
                        }
                    }
                });
                //call.cancel();
            }

例外:

E/AndroidRuntime: FATAL EXCEPTION: OkHttp Dispatcher
                                             Process: com.app, PID: 2660
                                             java.lang.IllegalStateException: closed
                                                 at okio.RealBufferedSource.rangeEquals(RealBufferedSource.java:398)
                                                 at okio.RealBufferedSource.rangeEquals(RealBufferedSource.java:392)
                                                 at okhttp3.internal.Util.bomAwareCharset(Util.java:449)
                                                 at okhttp3.ResponseBody.string(ResponseBody.java:174)
                                                 at com.ustork.CustomPlaces$2$1.onResponse(CustomPlaces.java:89)
                                                 at okhttp3.RealCall$AsyncCall.execute(RealCall.java:153)
                                                 at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
                                                 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
                                                 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
                                                 at java.lang.Thread.run(Thread.java:818)

1 个答案:

答案 0 :(得分:4)

如何尝试另一种方法解决您的问题?您可以使用OkHttp制作类似的内容而不使用asyncTask

Call call = new OkHttpClient().newCall(your request);
    call.enqueue(new Callback() { // call off UI thread.
        @Override
        public void onFailure(Call call, IOException e) {
            // this is where your call is cancelled: call.isCanceled()
        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {

        }
    });
    call.cancel(); // this is the proper way to cancel an async call.

更新

您应该注意到the response body is a one-shot value that may be consumed only once并且不应该两次致电response.body().string()。只需创建一个局部变量:responseString = response.body().string()并仅使用它。