@Override public Response intercept(Chain chain) throws IOException { Response response = chain.proceed(chain.request()); return response.newBuilder().body(new ProcessableResponse(response.body(), progressListeners)).build(); } 复制代码
okhttp添加拦截器,传入带有监听的ResponseBody实现下载监听。
↓
↓bash
既然核心是传入带有监听的ResponseBody,那么能不能在enqueue(Callback callback)回调里传入带有监听的responseBody呢(也就是如下代码)markdown
call.enqueue(new Callback() { @Override public void onResponse(Call call, Response response) throws IOException { response.newBuilder().body(new ProcessableResponse(response.body(), progressListeners)).build(); } }) 复制代码
行吗[伪装] ???网络
也就是说,在执行call的回调以前,Okio已经在读取数据了,若是咱们想要对下载进行监听,就必须在读取数据以前,把默认的responseBody包装成咱们能监听数据读取的responseBody。ide
既然要用拦截器来实现下载监听,通常是要在okhttp初始化阶段,而咱们的下载监听实际上就只有下载数据的时候须要用到,也就是说我想在要下载的时候才设置咱们的下载监听,下载完了,把它移除,可是↓ui
OkHttpClient(Builder builder) {
...
this.interceptors = Util.immutableList(builder.interceptors);
this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
...
}
复制代码
上面代码能够看到,okhttp在建立时就把拦截器设置成了不可修改的了,也就是说,后续咱们就不能动态的添加拦截器了~~this
根据okhttp拦截器嵌套执行的逻辑,咱们也能够模拟一个本身的拦截器的嵌套执行,而后和默认的拦截器串联在一块儿,来实现咱们想要的逻辑。spa
/** * 网络链接代理拦截器 * Created by yan on 8/20/18. */ class ProxyNetInterceptor implements Interceptor { private List<Interceptor> realInterceptors = new ArrayList<>(); @Override public Response intercept(@NonNull Chain chain) throws IOException { if (!realInterceptors.isEmpty()) { TempInterceptorChain tempInterceptorChain = new TempInterceptorChain(chain, realInterceptors, 0); return tempInterceptorChain.proceed(chain.request()); } return chain.proceed(chain.request()); } public void addRealInterceptor(Interceptor realInterceptor) { if (!realInterceptors.contains(realInterceptor)) { realInterceptors.add(realInterceptor); } } public void removeNetInterceptor(Interceptor netInterceptor) { realInterceptors.remove(netInterceptor); } private static class TempInterceptorChain implements Interceptor.Chain { private Chain realInterceptorChain; private List<Interceptor> realInterceptors; private int index; private TempInterceptorChain(Chain realInterceptorChain, List<Interceptor> realInterceptors, int index) { this.realInterceptorChain = realInterceptorChain; this.realInterceptors = realInterceptors; this.index = index; } @Override public Request request() { return realInterceptorChain.request(); } @Override public Response proceed(@NonNull Request request) throws IOException { final Chain next; if (index + 1 >= realInterceptors.size()) {// 把代理拦截器与本来的拦截器相链接 next = realInterceptorChain; } else { next = new TempInterceptorChain(realInterceptorChain, realInterceptors, index + 1); } Interceptor interceptor = realInterceptors.get(index); return interceptor.intercept(next);// 内部继续执行process 造成递归嵌套 } @Override public Connection connection() { return realInterceptorChain.connection(); } } } 复制代码
以上就是咱们的代理拦截器,能够咱们传入的拦截器集合(realInterceptors),嵌套进默认的拦截器执行集合里,这样也就能够实现对拦截器的动态管理了~~.net
既然咱们使用了okhttp,大几率也是要用到拦截器(除了下载监听,还有统一header设置,或者统一的错误码判断等),若是你的拦截器只有一段代码用到,其余地方不想用,能够试试这样的代理方式,方便动态管理。3d