如何使用OKHTTP取消请求

15

我需要使用OKHTTP管理一些请求,并使用Google Places AutoComplete通过输入地址来接收一些预测。问题在于,每次我插入一个字符时,它都会发出一个新的请求,但同时我需要取消之前的请求!例如:纽约市=同时进行13个请求!因此,我正在尝试使用单个Call实例来取消已请求的任何内容,但没有成功。这就是我所做的!

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 = client.newCall(request);


                call.enqueue(new Callback() {
                    public void onResponse(Call call, final Response response) throws IOException {
                        final String result = response.body().string();
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                Log.d("Response",result);
                                PlacePredictions place = null;
                                try {
                                    place = LoganSquare.parse(result,PlacePredictions.class);
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                                if(autoCompleteAdapter == null){
                                    autoCompleteAdapter = new AutoCompleteAdapter(CustomPlaces.this);
                                    recyclerView.setAdapter(autoCompleteAdapter);
                                    autoCompleteAdapter.Add(place.getPlaces());
                                }else {
                                    autoCompleteAdapter.Clear();
                                    autoCompleteAdapter.Add(place.getPlaces());
                                    autoCompleteAdapter.notifyDataSetChanged();
                                }
                            }
                        });
                    }
                    public void onFailure(Call call, IOException e) {
                        //fail();
                    }
                });
            }else {
                if(autoCompleteAdapter != null){
                    autoCompleteAdapter.Clear();
                }
            }
        }

我检查了call对象是否为null并取消了请求,但它仍然继续出现!

你为什么要为每个用户输入的字母创建一个请求?增加一些超时时间(例如1秒),只有用户在1秒内没有输入任何内容时才发送请求。我可以提供一个示例代码。 - babay
如果您能提供,那就太好了。谢谢! - Nathiel Barros
@NathielBarros - 用户再次做什么?作为标题的一部分吗? - RoCkDevstack
2个回答

20

以下内容怎么处理:

            //Set tags for your requests when you build them:
            Request request = new Request.Builder().
            url(url).tag("requestKey").build();

            //When you want to cancel:
            //A) go through the queued calls and cancel if the tag matches:
            for (Call call : mHttpClient.dispatcher().queuedCalls()) {
                if (call.request().tag().equals("requestKey"))
                    call.cancel();
            }

            //B) go through the running calls and cancel if the tag matches:
            for (Call call : mHttpClient.dispatcher().runningCalls()) {
                if (call.request().tag().equals("requestKey"))
                    call.cancel();
            }

好的,那么我将保留代码不变,只需要添加一个标签和两个“for”对吧?所以每次添加新字符时,我都要执行这个循环,这样就可以防止响应返回了? - Nathiel Barros
你需要先取消,然后再请求(这样你就不会取消新的请求了):-) 同时将cancelPending重构为一个方法。 - TomerBu

1
延迟向服务器发送请求,仅当输入在超时时间(1000毫秒,可根据需要调整)内未更改时才进行提交。您可以为GetHintsRequest添加取消方法。
...
    Address.addTextChangedListener(new TextWatcher() {
        @Override
        public void afterTextChanged(Editable s) {
            if (s.length() < 3) {
                if (autoCompleteAdapter != null) {
                    autoCompleteAdapter.Clear();
                }
                return;
            }

            GetHintsRequest request = new GetHintsRequest(s.toString(), new GetHintsRequest.GetHintsCallback() {
                @Override
                public boolean isRequestNotChanged(String oldRequest) {
                    return Address.getText().toString().equals(oldRequest);
                }

                @Override
                public void onGotHints(String request, PlacePredictions predictions) {
                    if (autoCompleteAdapter == null) {
                        autoCompleteAdapter = new AutoCompleteAdapter(CustomPlaces.this);
                        recyclerView.setAdapter(autoCompleteAdapter);
                        autoCompleteAdapter.Add(place.getPlaces());
                    } else {
                        autoCompleteAdapter.Clear();
                        autoCompleteAdapter.Add(place.getPlaces());
                        autoCompleteAdapter.notifyDataSetChanged();
                    }
                }
            });
            request.postCheck();
        }
    });
...

public class GetHintsRequest {
    private static final long TIMEOUT_MS = 1000; // timeout
    private final String requestText;
    private final GetHintsCallback callback;
    // android.os.Handler, can be used to post and delayed post to main thread. activity.runOnUiThread uses it
    private final Handler handler = new Handler(Looper.getMainLooper());

    public GetHintsRequest(String requestText, GetHintsCallback callback) {
        this.requestText = requestText;
        this.callback = callback;
    }

    public void postCheck() {
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (callback.isRequestNotChanged(requestText)){
                    execute();
                }
            }
        }, TIMEOUT_MS);
    }


    public void execute() {
        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 = client.newCall(request);

        call.enqueue(new Callback() {
            public void onResponse(Call call, final Response response) throws IOException {
                final String result = response.body().string();
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        Log.d("Response", result);
                        PlacePredictions place = null;
                        if (callback.isRequestNotChanged(requestText)) {
                            try {
                                place = LoganSquare.parse(result, PlacePredictions.class);
                            } catch (IOException e) {
                                e.printStackTrace();
                                return;
                            }
                            callback.onGotHints(requestText, place);
                        }
                    }
                });
            }

            public void onFailure(Call call, IOException e) {
                //fail();
            }
        });
    }

    public interface GetHintsCallback {
        boolean isRequestNotChanged(String oldRequest);

        void onGotHints(String request, PlacePredictions predictions);
    }

}

谢谢!我会尝试的。对我来说最大的问题是每次放置东西时取消请求。 - Nathiel Barros

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接