web-dev-qa-db-ja.com

Squareのレトロフィットクライアントを使用して、進行中のリクエストをキャンセルすることはできますか?もしそうなら?

SquareのRetrofitクライアントを使用して、Android Appからjsonリクエストを短期間有効にします。リクエストをキャンセルする方法はありますか?ある場合、その方法は?

18
Alfie Hanssen

非同期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.
}
_

あるいは、ExecutorCompletionServicepoll(timeout, TimeUnit.MILISECONDS)またはtake()のいずれかの進行中のタスクを使用することもできます。これにより、shutdownNow()の場合と同様に、スレッドプールがシャットダウンされなくなり、ExecutorServiceを再利用できます。

それが誰かのために役立つことを願っています。

Edit:OkHttp 2以降 RC1changelog.cancel(Object tag)を実行すると可能。今後のレトロフィットでも同じ機能が期待できます。

実際のRequestオブジェクトを使用してキャンセルできます

okClient.cancel(request);

または、_Request.Builder_にタグを指定した場合は、

okClient.cancel(request.tag());

進行中、実行済み、または保留中のすべてのリクエストは、DispatcherokClient.getDispatcher()内でキューに入れられます。このオブジェクトでキャンセルメソッドを呼び出すこともできます。 Cancelメソッドは、すでに確立されている場合、ホストへの接続を強制終了するようOkHttp Engineに通知します。

編集2:Retrofit 2には、キャンセルのリクエストが完全に機能しています。

22

回答に基づいてキャンセル可能なコールバッククラスを実装しました 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);
3
Biggemot

コールバックを実装するデリゲートオブジェクトでコールバックもラップします。いくつかのメソッドを呼び出してデリゲートをクリアし、応答を受け取ったときに常に何もしないようにします。

次の議論を見てください

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

より良い戦略は、コールバックの実行をキャンセルすることです

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

3
diesel

これはレトロフィット2.0の場合で、メソッドcall.cancel()があり、実行中の呼び出しもキャンセルされます。以下はそのドキュメント定義です。

retrofit2.Call

public abstract void cancel()

この通話をキャンセルします。処理中の呼び出しをキャンセルする試みが行われ、呼び出しがまだ実行されていない場合は行われません。

2
AAnkit

最新バージョンのRetrofit V 2.0.0.beta2には簡単な方法があります。再試行も実装できます。
ここを見てください retrofit.client.UrlConnectionClientがクライアントとして使用されている場合に、レトロフィットで進行中のリクエストをキャンセルする方法

1
cgr

リンク経由のRetrofit 2.0ベータ3の変更ログによると https://github.com/square/retrofit/releases/tag/parent-2.0.0-beta

New:isCanceled()メソッドは、呼び出しがキャンセルされたかどうかを返します。これをonFailureで使用して、コールバックがキャンセルから呼び出されたか、実際のトランスポート障害から呼び出されたかを判別します。

これは物事を簡単にする必要があります。

1
CarlosRivin

少し遅れるかもしれませんが、解決策を見つけた可能性があります。リクエストが実行されるのを防ぐことはできませんでしたが、実行されたリクエストに満足し、何もしない場合は、私が作成した this の質問と回答を確認してください。

0
Vektor88