同步请求
1、创建一个请求对象
Call call = OkHttpClient.newCall(this);
2、获取请求结果
call.execute();
Call 对象exexcute()方法分析
@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 {
client.dispatcher().finished(this);
}
}
在同步代码中,先通过判断executed标识,如果当前已经有在执行,则会抛出"Already Executed"信息的异常,如果没有执行过,则更改executed标识为true。一个任务只能执行一次
captureCallStackTrace()方法:
主要用于捕捉一些http请求的异常堆栈信息
eventListener.callStart(this)方法:
开启事件监听
该方法源码
/**
* Invoked as soon as a call is enqueued or executed by a client. In case of thread or stream
* limits, this call may be executed well before processing the request is able to begin.
*
* <p>This will be invoked only once for a single {@link Call}. Retries of different routes
* or redirects will be handled within the boundaries of a single callStart and {@link
* #callEnd}/{@link #callFailed} pair.
*/
public void callStart(Call call) {
}
该方法
一旦调用被客户端排队或执行,就会立即调用。在线程或流受限的情况下,次调用可能在处理请求能在开始之前调用,也就是说该方法会在调用Call对象的enqueue()或execute()方法的时候,就会开启这个listener
client.dispatcher().executed(this)方法
受限调用OkHttpClient的dispatcher()方法,该方法返回一个Dispatcher对象,紧接着调用该对象的executed()方法;该方法中,runningSyncCalls是一个存放同步请求的队列,这里仅仅只是将RealCall加入到同步请求的队列中
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<>();
readyAsyncCalls 是异步请求的就绪队列
runningAsyncCalls 是异步请求的执行队列
runningSyncCalls 是同步请求的执行队列
3、Response result = getResponseWithInterceptorChain()方法
获取请求结果,由此可见,同步请求并没有使用线程池
也没有开启子线程
4、client.dispatcher().finished(this)方法
在finally中执行
通过调用Dispatcher的finished()方法,传入当前的RealCall对象
/** Used by {@code Call#execute} to signal completion. */
void finished(RealCall call) {
finished(runningSyncCalls, call);
}
private <T> void finished(Deque<T> calls, T call) {
Runnable idleCallback;
synchronized (this) {
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
idleCallback = this.idleCallback;
}
boolean isRunning = promoteAndExecute();
if (!isRunning && idleCallback != null) {
idleCallback.run();
}
}
该方法继续调用了其他一个同名的的方法,将正在执行的同步请求队列传了进来,在同步代码块中,移除掉同步请求队列中的call对象,并进行了判断,如果移除出错,则会抛出异常。接着判断promoteCalls,由于这里传入的promoteCalls为false,所以不会走promoteCalls()方法。
异步请求
@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));
}
client.dispatcher().enqueue(new AsyncCall(responseCallback))
调用Dispatcher的enqueue()方法,将Callback回调封装成AsyncCall对象作为参数传入
AsyncCall对象继承自NamedRunnable对象,而NamedRunnable对象实现了Runnable接口
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
该方法前加了synchronized修饰符,是一个同步方法,根据判断当前执行的异步请求数是否小于maxRequests(最大请求数,默认为64) 且当前执行的异步请求队列中相同主机的请求数小于maxRequestsPerHost(每个主机最大请求数,默认为5) 来进行处理,如果二者都小于设置的值,则将该请求添加到runningAsyncCalls(异步请求执行队列)中,否则则添加到readyAsyncCalls(异步请求准备队列)中。