Skip to content Skip to sidebar Skip to footer

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. Is there a way to cancel a request? If so, how?

Solution 1:

For canceling async Retrofit request, you can achieve it by shutting down the ExecutorService that performs the async request.

For example I had this code to build the RestAdapter:

BuilderrestAdapter=newRestAdapter.Builder();
restAdapter.setEndpoint(BASE_URL);
restAdapter.setClient(okClient);
restAdapter.setErrorHandler(mErrorHandler);
mExecutorService = Executors.newCachedThreadPool();
restAdapter.setExecutors(mExecutor, newMainThreadExecutor());
restAdapter.setConverter(newGsonConverter(gb.create()));

and had this method for forcefully abandoning the requests:

publicvoidstopAll(){
   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. This will prevent thread pool not being shut down, as it would do with shutdownNow() and so you could reuse your ExecutorService

Hope it would be of help for someone.

Edit: As of OkHttp 2 RC1changelog performing a .cancel(Object tag) is possible. We should expect the same feature in upcoming Retrofit:

You can use actual Request object to cancel it

okClient.cancel(request);

or if you have supplied tag to Request.Builder you have to use

okClient.cancel(request.tag());

All ongoing, executed or pending requests are queued inside Dispatcher, okClient.getDispatcher(). You can call cancel method on this object too. Cancel method will notify OkHttp Engine to kill the connection to the host, if already established.

Edit 2: Retrofit 2 has fully featured canceling requests.

Solution 2:

Wrap the callback in a delegate object that implements Callback as well. 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

Better strategy would be canceling the callback execution

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

Solution 3:

I've implemented cancelable callback class based on answer https://stackoverflow.com/a/23271559/5227676

publicabstractclassCancelableCallback<T> implementsCallback<T> {

    privatestatic List<CancelableCallback> mList = new ArrayList<>();

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

    publicstaticvoidcancelAll() {
        Iterator<CancelableCallback> iterator = mList.iterator();
        while (iterator.hasNext()){
            iterator.next().isCanceled = true;
            iterator.remove();
        }
    }

    publicstaticvoidcancel(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();
                }
            }
        }
    }

    publicCancelableCallback() {
        mList.add(this);
    }

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

    publicvoidcancel() {
        isCanceled = true;
        mList.remove(this);
    }

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

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

    publicabstractvoidonSuccess(T t, Response response);

    publicabstractvoidonFailure(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 allCancelableCallback.cancelAll();
// or cancel by tagCancelableCallback.cancel(TAG);

Solution 4:

This is for retrofit 2.0, the method call.cancel() is there which cancels the in-flight call as well. below is the document definition for it.

retrofit2.Call

publicabstractvoidcancel()

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.

Solution 5:

Now there is an easy way in latest version of 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?

Post a Comment for "Using Square's Retrofit Client, Is It Possible To Cancel An In Progress Request? If So How?"