简体   繁体   English

使用Square的Retrofit Client,是否可以取消进行中的请求?如果是这样的话?

[英]Using Square's Retrofit Client, is it possible to cancel an in progress request? If so how?

I'm using Square's Retrofit Client to make short-lived json requests from an Android App. 我正在使用Square的Retrofit Client从Android应用程序发出短期json请求。 Is there a way to cancel a request? 有办法取消请求吗? If so, how? 如果是这样,怎么样?

For canceling async Retrofit request, you can achieve it by shutting down the ExecutorService that performs the async request. 要取消异步Retrofit请求,可以通过关闭执行异步请求的ExecutorService来实现。

For example I had this code to build the RestAdapter : 例如,我有这个代码来构建RestAdapter

Builder restAdapter = new RestAdapter.Builder();
restAdapter.setEndpoint(BASE_URL);
restAdapter.setClient(okClient);
restAdapter.setErrorHandler(mErrorHandler);
mExecutorService = Executors.newCachedThreadPool();
restAdapter.setExecutors(mExecutor, new MainThreadExecutor());
restAdapter.setConverter(new GsonConverter(gb.create()));

and had this method for forcefully abandoning the requests: 并有这种方法强行放弃请求:

public void stopAll(){
   List<Runnable> pendingAndOngoing = mExecutorService.shutdownNow();
   // probably await for termination.
}

Alternatively you could make use of ExecutorCompletionService and either poll(timeout, TimeUnit.MILISECONDS) or take() all ongoing tasks. 或者,您可以使用ExecutorCompletionServicepoll(timeout, TimeUnit.MILISECONDS)take()所有正在进行的任务。 This will prevent thread pool not being shut down, as it would do with shutdownNow() and so you could reuse your ExecutorService 这将阻止线程池不被关闭,就像shutdownNow() ,因此您可以重用ExecutorService

Hope it would be of help for someone. 希望它会对某人有所帮助。

Edit : As of OkHttp 2 RC1 changelog performing a .cancel(Object tag) is possible. 编辑 :从OkHttp 2开始,执行.cancel(Object tag) RC1 更改日志是可能的。 We should expect the same feature in upcoming Retrofit: 我们应该期待即将推出的Retrofit中的相同功能:

You can use actual Request object to cancel it 您可以使用实际的Request对象来取消它

okClient.cancel(request);

or if you have supplied tag to Request.Builder you have to use 或者,如果您向Request.Builder提供了标签,则必须使用

okClient.cancel(request.tag());

All ongoing, executed or pending requests are queued inside Dispatcher , okClient.getDispatcher() . 所有正在进行,已执行或待处理的请求都在DispatcherokClient.getDispatcher()内排队。 You can call cancel method on this object too. 您也可以在此对象上调用cancel方法。 Cancel method will notify OkHttp Engine to kill the connection to the host, if already established. 如果已经建立,取消方法将通知OkHttp Engine终止与主机的连接。

Edit 2 : Retrofit 2 has fully featured canceling requests. 编辑2 :Retrofit 2具有全功能的取消请求。

Wrap the callback in a delegate object that implements Callback as well. 将回调包装在一个实现Callback的委托对象中。 Call some method to clear out the delegate and have it just no-op whenever it gets a response. 调用一些方法来清除委托,并在得到响应时让它只是无操作。

Look at the following discussion 请看以下讨论

https://plus.google.com/107765816683139331166/posts/CBUQgzWzQjS https://plus.google.com/107765816683139331166/posts/CBUQgzWzQjS

Better strategy would be canceling the callback execution 更好的策略是取消回调执行

https://stackoverflow.com/a/23271559/1446469 https://stackoverflow.com/a/23271559/1446469

I've implemented cancelable callback class based on answer https://stackoverflow.com/a/23271559/5227676 我已根据答案https://stackoverflow.com/a/23271559/5227676实现了可取消的回调类

public abstract class CancelableCallback<T> implements Callback<T> {

    private static List<CancelableCallback> mList = new ArrayList<>();

    private boolean isCanceled = false;
    private Object mTag = null;

    public static void cancelAll() {
        Iterator<CancelableCallback> iterator = mList.iterator();
        while (iterator.hasNext()){
            iterator.next().isCanceled = true;
            iterator.remove();
        }
    }

    public static void cancel(Object tag) {
        if (tag != null) {
            Iterator<CancelableCallback> iterator = mList.iterator();
            CancelableCallback item;
            while (iterator.hasNext()) {
                item = iterator.next();
                if (tag.equals(item.mTag)) {
                    item.isCanceled = true;
                    iterator.remove();
                }
            }
        }
    }

    public CancelableCallback() {
        mList.add(this);
    }

    public CancelableCallback(Object tag) {
        mTag = tag;
        mList.add(this);
    }

    public void cancel() {
        isCanceled = true;
        mList.remove(this);
    }

    @Override
    public final void success(T t, Response response) {
        if (!isCanceled)
            onSuccess(t, response);
        mList.remove(this);
    }

    @Override
    public final void failure(RetrofitError error) {
        if (!isCanceled)
            onFailure(error);
        mList.remove(this);
    }

    public abstract void onSuccess(T t, Response response);

    public abstract void onFailure(RetrofitError error);
}

Usage example 用法示例

rest.request(..., new CancelableCallback<MyResponse>(TAG) {
    @Override
    public void onSuccess(MyResponse myResponse, Response response) {
        ...
    }

    @Override
    public void onFailure(RetrofitError error) {
       ...
    }
});

// if u need to cancel all
CancelableCallback.cancelAll();
// or cancel by tag
CancelableCallback.cancel(TAG);

This is for retrofit 2.0, the method call.cancel() is there which cancels the in-flight call as well. 这是为了改进2.0,方法call.cancel()也在那里取消了正在进行的调用。 below is the document definition for it. 下面是它的文档定义。

retrofit2.Call

public abstract void cancel()

Cancel this call. 取消此通话。 An attempt will be made to cancel in-flight calls, and if the call has not yet been executed it never will be. 将尝试取消正在进行的呼叫,如果呼叫尚未执行,则永远不会。

Now there is an easy way in latest version of Retrofit V 2.0.0.beta2. 现在,最新版本的Retrofit V 2.0.0.beta2有一个简单的方法。 Can implement retry too. 也可以实现重试。
Take a look here How to cancel ongoing request in retrofit when retrofit.client.UrlConnectionClient is used as client? 看看这里当retrofit.client.UrlConnectionClient用作客户端时,如何在改造中取消正在进行的请求?

According to the Retrofit 2.0 beta 3 changelog via link https://github.com/square/retrofit/releases/tag/parent-2.0.0-beta3 根据Retrofit 2.0 beta 3 changelog通过链接https://github.com/square/retrofit/releases/tag/parent-2.0.0-beta3

New: isCanceled() method returns whether a Call has been canceled. 新增:isCanceled()方法返回是否已取消呼叫。 Use this in onFailure to determine whether the callback was invoked from cancelation or actual transport failure. 在onFailure中使用它来确定是否从取消或实际传输失败中调用了回调。

This should make stuff easier. 这应该让事情变得更容易。

I might be a bit late, but I've possibly found a solution. 我可能有点晚了,但我可能找到了解决方案。 I haven't been able to prevent a request from being executed, but if you're satisfied with the request being performed and not doing anything, you might check this question and answer, both made by me. 我一直没能防止执行的请求,但如果你感到满意,正在执行的请求,并没有做任何事情,你可能要检查这个问题和回答,无论是我做的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM