基本用法
String url = "http://wwww.baidu.com";
OkHttpClient okHttpClient = new OkHttpClient();
final Request request = new Request.Builder()
.url(url)
.post()
.build();
Call call = okHttpClient.newCall(request);
//异步请求
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: 异步请求失败 ");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, "onResponse: 异步请求成功 " + response.body().string());
}
});
//同步请求
Response response = client.newCall(request).execute();//得到Response 对象(会阻塞当前线程)
跟到深处会发现无论同步和异步请求的关键都是拦截器方法
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
}
接下来就以该方法为入口分析下OkHttp3的代码
拦截器调用流程
再贴贴上面的代码分析一下
//RealCall.Java
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
// 建立拦截器列表
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());//自定义的拦截器,例如日志打印拦截器
interceptors.add(retryAndFollowUpInterceptor);//重连及重定向拦截器
interceptors.add(new BridgeInterceptor(client.cookieJar()));//桥拦截器?主要是用来加Header信息
interceptors.add(new CacheInterceptor(client.internalCache()));//缓存拦截器
interceptors.add(new ConnectInterceptor(client));//连接拦截器,用于建立连接
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());//仅在建立WebSocket时才会加的拦截器
}
interceptors.add(new CallServerInterceptor(forWebSocket));//发送信息拦截器(之前的连接拦截器负责建立连接但是啥也没干,这个拦截器负责给服务器发消息并接收返回)
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);//开启链式调用
}
这里主要是拦截器的大概调用流程,首先添加自定义的拦截器(一般是日志打印拦截器或者再增加Header信息之类的),然后添加其他固定的拦截器,注意这里的拦截器顺序都是固定的,添加后用一个RealInterceptorChain包装并依次调用,执行顺序就是添加拦截器的顺序,这里每个的拦截器都是继承了Interceptor接口
public interface Interceptor {
//拦截器子类 需复写的方法,基本每个拦截器的具体用法都在这个函数里面
Response intercept(Chain chain) throws IOException;
//拦截器调用链继承接口
interface Chain {
Request request();
Response proceed(Request request) throws IOException;
@Nullable Connection connection();
Call call();
int connectTimeoutMillis();
Chain withConnectTimeout(int timeout, TimeUnit unit);
int readTimeoutMillis();
Chain withReadTimeout(int timeout, TimeUnit unit);
int writeTimeoutMillis();
Chain withWriteTimeout(int timeout, TimeUnit unit);
}
}
再看看Chain子类RealInterceptorChain的关键方法proceed
//带Response返回,方便做二次处理
@Override public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpCodec, connection);
}
//这里仅贴出关键代码,该函数其他代码都是条件判断和返回处理
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
.........
// 调用核心:直接index+1其他参数不变来调用下一个Interceptor
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
...........
return response;
}
由此看出该方法主要是负责调用链的运转,当某个Interceptor在处理好大部分工作(注意这里说大部分是因为通过后面的Interceptor返回可以再做第二次处理,类似与Android View的触摸事件下发)后直接把原来的request丢过去调用chain.proceed(request),RealInterceptorChain类就会自动通过index+1来调用下一个Interceptor
。这里也可以看出虽然方法内一直next next next的 又有Chain这样的字眼让人误以为内部是链表结构存放Interceptor,其实是通过列表存放的
这里顺带科普一下列表和链表的大概优缺点(给自己看。。。。)
https://blog.csdn.net/st1441517927/article/details/99483738
总结
OkHttp通过拦截器设计模式非常的巧妙,一来是细化各个分功能解耦度高,层次分明,二来是方便定制(可以自定义拦截器), 再者采用类似Android 触摸事件分发的机制,使得每个Interceptor可以进行二次处理,非常关键,某些需要二次处理(或重点处理返回那一次)的就得益于这种机制,例如重定向拦截器和自定义的日志拦截器尤为明显