Можно ли отменить текущий запрос с помощью клиента Square Retrofit? Если да, то как?

Я использую клиент Square Retrofit для выполнения кратковременных запросов json из приложения Android. Есть ли способ отменить запрос? Если да, то как?


person Alfie Hanssen    schedule 08.08.2013    source источник
comment
какие-либо обновления по этому поводу? у меня такая же проблема   -  person Romain Piel    schedule 29.08.2013
comment
К сожалению, нет, хотя я только что зарегистрировал эту проблему.   -  person Alfie Hanssen    schedule 29.08.2013
comment
да, я обнаружил это позже, похоже, это в их планах...   -  person Romain Piel    schedule 30.08.2013


Ответы (7)


Чтобы отменить асинхронный запрос Retrofit, вы можете отключить ExecutorService, который выполняет асинхронный запрос.

Например, у меня был этот код для сборки 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()));

и имел этот метод для принудительного отказа от запросов:

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

В качестве альтернативы вы можете использовать ExecutorCompletionService и либо poll(timeout, TimeUnit.MILISECONDS), либо take() все текущие задачи. Это предотвратит закрытие пула потоков, как это было бы с shutdownNow(), и поэтому вы можете повторно использовать свой ExecutorService

Надеюсь, кому-то это поможет.

Изменить: начиная с OkHttp 2 RC1 журнал изменений возможно выполнение .cancel(Object tag). Мы должны ожидать ту же функцию в предстоящей модернизации:

Вы можете использовать фактический объект Request, чтобы отменить его.

okClient.cancel(request);

или если вы предоставили тег Request.Builder, вы должны использовать

okClient.cancel(request.tag());

Все текущие, выполненные или ожидающие запросы помещаются в очередь внутри Dispatcher, okClient.getDispatcher(). Вы также можете вызвать метод отмены для этого объекта. Метод Cancel уведомит OkHttp Engine о разрыве соединения с хостом, если оно уже установлено.

Редактировать 2. Дооснащение 2 имеет полнофункциональные запросы на отмену.

person Nikola Despotoski    schedule 26.02.2014
comment
В каком потоке должен выполняться shutdownNode? Потому что в настоящее время я выполняю это в потоке пользовательского интерфейса, и запрос/передача вообще не отменяется. - person Konrad Reiche; 13.08.2014
comment
Вы также пытались дождаться завершения после вызова shutdownNow()? - person Nikola Despotoski; 13.08.2014
comment
Нет, но какая разница? - person Konrad Reiche; 14.08.2014
comment
@NikolaDespotoski, как использовать Request.Builder при модернизации - person SHASHIDHAR MANCHUKONDA; 17.07.2015
comment
Можете ли вы привести пример кода, который работает? Я понятия не имею, как это сделать. - person Subkhan Sarif; 14.01.2016

Оберните обратный вызов в объект делегата, который также реализует обратный вызов. Вызовите какой-нибудь метод, чтобы очистить делегата и заставить его просто не работать всякий раз, когда он получает ответ.

Посмотрите на следующее обсуждение

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

Лучшей стратегией будет отмена выполнения обратного вызова

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

person diesel    schedule 09.10.2013
comment
Обратите внимание, что ответы только по ссылкам не рекомендуются, ответы SO должны быть конечной точкой поиска. для решения (по сравнению с еще одной остановкой ссылок, которые со временем устаревают). Пожалуйста, рассмотрите возможность добавления здесь отдельного синопсиса, оставив ссылку в качестве ссылки. - person kleopatra; 09.10.2013

Я реализовал отменяемый класс обратного вызова на основе ответа 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);
}

Пример использования

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);
person Biggemot    schedule 14.08.2015
comment
Хорошее решение, но ваши cancelAll и cancel(ObjectTag) вызовут java.util.ConcurrentModificationException, когда вы удалите объект из списка без итератора. Перебрать список с помощью итератора. - person voytez; 07.02.2016

Это для модификации 2.0, есть метод call.cancel(), который также отменяет вызов в полете. ниже приведено определение документа для него.

retrofit2.Call

public abstract void cancel()

Отменить вызов. Будет предпринята попытка отменить текущие вызовы, и если вызов еще не был выполнен, он никогда не будет выполнен.

person AAnkit    schedule 10.03.2016

Теперь есть простой способ в последней версии Retrofit V 2.0.0.beta2. Также можно реализовать повторную попытку.
Посмотрите здесь Как отменить текущий запрос в модификации, когда в качестве клиента используется retrofit.client.UrlConnectionClient?

person cgr    schedule 01.10.2015

Согласно журналу изменений Retrofit 2.0 beta 3 по ссылке https://github.com/square/retrofit/releases/tag/parent-2.0.0-beta3

Новое: метод isCanceled() возвращает, был ли вызов отменен. Используйте это в onFailure, чтобы определить, был ли обратный вызов вызван отменой или фактическим сбоем транспорта.

Это должно облегчить задачу.

person CarlosRivin    schedule 11.01.2016

Я могу немного опоздать, но я, возможно, нашел решение. Мне не удалось предотвратить выполнение запроса, но если вы удовлетворены выполнением запроса и ничего не делаете, вы можете проверить этот вопрос и ответ, оба сделаны мной.

person Vektor88    schedule 24.04.2014