定义:Okhttp是对Socket的封装。有三个主要的类,Request,Response,Call
默认使用new OkHttpClient() 创建初client对象。
如果需要初始化网络请求的参数,如timeout,interceptor等,可以创建Builder,通过builder.build() 创建初client对象。
三个问题
1.请求发送到什么哪去了?框架里放到哪里了?
请求通过execute方法发送到框架中的两个队列中去了:运行中的队列;等待中的队列,如果说运行中的队列总数小于64并且访问同一目标机器请求小于5,就进入运行队列,否则进入等待队列
2.请求被谁处理:请求提交到运行中队列后,交给线程池来处理,直接处理请求
3.请求是怎么被维护的:每次请求完成后,client.dispath调用finished方法,对运行中的队列和等待中的队列进行数据处理,(在符合条件的情况下,将等待中的加入到运行中队列中去)
流程
1.通过
生成一个OkHttpClient client = new OkHttpClient();
2.构建一个Request requet = new Request.Builder()
.get().url("https:www.baidu.com").build();
3.通过client.newCall(request)得到Call,这个call是他的子类RealCall
4.通过call.execute(同步) 或call.enqueue(异步)启动
A:执行Execute
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Execu
ted"); // (1)
executed = true;
}
try { client.dispatcher().executed(this);
// (2)
Response result = getResponseWithInterceptorChain();
// (3)
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this); // (4)
} }
1.先判断这个call是否被执行了,每个call只能被执行一次,如果要一个完成一样的call可以利用call的clone方法进行克隆
2.利用client.dispathcer().execute(this)来进行执行,其中dispatcher.execute方法为
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
这里我刚开始没有相同,之后他加入队列后怎么调用的,后来发现在 下一个方法调用的
3.调用getResponseWithInterceptorChain函数来获取HTTP返回的结果,这里的originalRequest就是我们的请求刚刚加入队列的是RealCall,通过chain.proceed(originalRequest)去调用
private Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List 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 (!retryAndFollowUpInterceptor.isForWebSocket()) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(
retryAndFollowUpInterceptor.isForWebSocket()));
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
4.最后还要通知dispathcer自己已经执行完毕
client.dispatcher().finished(this);
会执行finished(队列、call,true)
其中这个方法是同步和异步都调用的方法,通过第三个参数,是否执行promoteCall方法具体的执行会不同,promoteCall方法
private void finished(Deque calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
//TODO calls 移除队列
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
//TODO 检查是否为异步请求,检查等候的队列 readyAsyncCalls,如果存在等候队列,则将等候队列加入执行队列
if (promoteCalls) promoteCalls();
//TODO 运行队列的数量
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
//闲置调用
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
private void promoteCalls() {
//TODO 检查 运行队列 与 等待队列
if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
//TODO 将等待队列加入到运行队列中
for (Iterator i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
//TODO 相同host的请求没有达到最大,加入运行队列
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
B执行Enqueue
// RealCall.java
@Override public void enqueue(Callback responseCallback) {
synchronized (this) { // 如果这个 call 已经被执行过,抛异常
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
//TODO 执行异步请求
synchronized void enqueue(AsyncCall call) {
//TODO 同时请求不能超过并发数(64,可配置调度器调整)
//TODO okhttp会使用共享主机即 地址相同的会共享socket
//TODO 同一个host最多允许5条线程通知执行请求
if (runningAsyncCalls.size() < maxRequests &&
runningCallsForHost(call) < maxRequestsPerHost) {
//TODO 加入运行队列 并交给线程池执行
runningAsyncCalls.add(call);
//TODO AsyncCall 是一个runnable,放到线程池中去执行,查看其execute实现
executorService().execute(call);
} else {
//TODO 加入等候队列
readyAsyncCalls.add(call);
}
}