Retrofit 2/OkHttp:取消所有正在运行的请求

19

我正在使用 Retrofit 2-beta2 和 OkHttp 2.7.0。

要从 Retrofit 中获取 OkHttpClient 对象,我使用的是 Retrofit .client() 方法,并调用其 cancel(Object tag) 方法取消所有正在运行的请求,但是请求仍然在运行并返回响应。

即使客户端的 DispatchergetQueuedCallCount()getRunningCallCount() 在调用 cancel() 后返回 0。

还需要做其他事情才能使其工作吗?或者这可能是 OkHttp 的一个 bug 吗?

作为解决方法,我在客户端的 ExecutorService 上调用了 shutdownNow(),但我希望有一个更干净的解决方案。


经过查看源代码,我现在明白为什么这不起作用了。我正在使用拦截器设置Request上的标签,因此创建了一个新的Request对象。OkHttpClient.cancel(Object tag)没有任何作用,因为原始的Request(在其中调用cancel(),因为它存在于Dispatcher的请求队列中)仍然没有设置标签。似乎Retrofit没有公开任何方法或接口来在原始的Request对象上设置标签。 - timemanx
1个回答

31

更新: 在OkHttp 3中,使用具有cancelAll()方法的Dispatcher可以更轻松地实现此操作。可以从OkHttpClient.dispatcher()中获取调度程序。

旧解决方案: 我所能找到的唯一方法是创建OkHttpClient的子类并将其与Retrofit一起使用。

class OkHttpClientExt extends OkHttpClient {
    static final Object TAG_CALL = new Object();

    @Override
    public Call newCall(Request request) {
        Request.Builder requestBuilder = request.newBuilder();
        requestBuilder.tag(TAG_CALL);
        return super.newCall(requestBuilder.build());
    }
}

以下一行代码会取消所有带有标签 TAG_CALL 的请求。由于上文中的类为所有请求设置了 TAG_CALL 标签,因此所有请求都将被取消。

retrofit.client().cancel(OkHttpClientExt.TAG_CALL);

1
不必扩展 OkHttpClient,您只需添加一个 RequestInterceptor 并为每个请求添加标记即可。 - Matthew
6
@Matthew 是的,使用 Interceptor 设置标签也能起到同样的效果。但是,从 OkHttp 3 开始,这已经不再需要了,因为 Dispatcher 提供了 cancelAll() 方法来取消所有请求,无论它们的标签是什么。 - timemanx
3
不知道Dispatcher类,非常有帮助! - Matthew
我无法从 OkHttpClient.Builder 或 Retrofit 实例中访问 dispatcher() 方法和 cancelAll() 方法。请提供一个完整的示例。 - Madhan
1
@Madhan你可以从OkHttpClient.Builder.build()返回的OkHttpClient实例中访问dispatcher()。http://square.github.io/okhttp/3.x/okhttp/okhttp3/OkHttpClient.html#dispatcher--http://square.github.io/okhttp/3.x/okhttp/okhttp3/OkHttpClient.Builder.html#build-- - timemanx

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