@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