前言
关于okhttp在Android开发中经常使用到,但是最近在从okhttp 2.0升级之后,发现改动的内容蛮大,在各种研究整理后,发现okhttp 不是几天就能够钻研透,现将自己的总结与思考做个小结,后面会持续read the fuck code.
架构
这篇博客主要是从okhttp的总体流程分析源码的执行过程,对okhttp源码有大体上的理解,从全局上看出okhttp的设计思想。先上一张自己总结的图,后面会由开始基础使用逐渐升入。

okhttp的整体基本流程基本上就是这个图了,简单概括可以做如下说明:
- 采用建造者设计模式创建okhttpclient 对象和请求request对象。
- 采用newCall 方法来生成真正的请求对象。
- 请求分为同步和异步两种方式,最终均是通过getResponseWithInterceptorChain 方法来实现网络请求。
分析
1 client 创建方式:
默认创建方式
public OkHttpClient() {
this(new Builder());
}
创建者创建方式
public OkHttpClient build() {
return new OkHttpClient(this);
}
- Request 创建方式:
Request(Builder builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = builder.headers.build();
this.body = builder.body;
this.tags = Util.immutableMap(builder.tags);
}
可以看出对于Request 也是一个构造者模式,那么我们来看一下builder构造方法:
public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}
会指定默认的方法和header。
无论是client还是request,亦或者是header都是使用创建者设计模式,整个模式在OKHttp中使用的非常多。
3 . 同步请求方式
构建完Request后,我们就需要构建一个Call,一般都是这样的Call call = mOkHttpClient.newCall(request);
通过call去执行相关的同步请求。
Response response = client.newCall(request).execute();
response 即为请求结果。
- 异步请求方式
同样也是需要构造一个Call对象,请求方式如下:
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
可以看出两者的请求方式都是通过一个Call 对象去执行,那么我们可以去看下这个call对象是什么了。查看源码可以看出newCall方法:
/**
* Prepares the {@code request} to be executed at some point in the future.
*/
@Override
public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
最终都是返回RealCall对象。RealCall构造方法如下:
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client);
this.timeout = new AsyncTimeout() {
@Override protected void timedOut() {
cancel();
}
};
this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS);
}
可以看出会判断是否是WebScoket 和增加一个默认的Interceptor--RetryAndFollowUpInterceptor。
正同架构图中所介绍一样,会有各种Interceptor。
同步与异步方法
- 同步方法:
@Override
public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
timeout.enter();
eventListener.callStart(this);
try {
//执行同步请求,其实是将同步任务添加到集合中
client.dispatcher().executed(this);
//执行网络请求
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
e = timeoutExit(e);
eventListener.callFailed(this, e);
throw e;
} finally {
//无论结果如何均会调用finish 方法
client.dispatcher().finished(this);
}
}
getResponseWithInterceptorChain 为网络请求相关方法,可以看到无论只想结果如何都会执行dispatcher对象的finish 方法。
2.异步方法:
@Override
public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
继续查看:
void enqueue(AsyncCall call) {
synchronized (this) {
readyAsyncCalls.add(call);
// Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
// the same host.
if (!call.get().forWebSocket) {
AsyncCall existingCall = findExistingCallWithHost(call.host());
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
}
}
promoteAndExecute();
}
对于Dispatcher 类主要关注这几个集合:
/**
* Ready async calls in the order they'll be run.
* 将要执行的异步任务集合
*/
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
/**
* Running asynchronous calls. Includes canceled calls that haven't finished yet.
* 正在执行的异步任务集合
*/
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
/**
* Running synchronous calls. Includes canceled calls that haven't finished yet.
* 同步任务的集合
*/
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
以上为一个简单分析,后面会依次查看原来来分析okhttp的相关源码。
网友评论