前面创建了Call对象,接下来就是执行。执行又分为了同步执行和异步执行,先看同步执行过程。
还是之前的过程:
//步骤1:创建OkHttpClient对象
OkHttpClient client = new OkHttpClient.Builder()
.readTimeout(5, TimeUnit.SECONDS)
.build();
//步骤2:创建Request对象
Request request = new Request.Builder()
.url("http://www.baidu.com")
.get()
.build();
//步骤3:创建Call对象
Call call = client.newCall(request);
//步骤4:进行请求
//异步请求方式
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
System.out.println("Fail");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
System.out.println(response.body().string());
}
});
//同步请求方式
Response response = call.execute();
通过Call对象的execute方法来完成同步请求,这个方法会一直阻塞至请求结果返回,或者请求过程出现错误。
同步请求–NewCall#execute方法的实现
@Override public Response execute() throws IOException {
synchronized (this) {//锁住这个Call对象
if (executed) throw new IllegalStateException("Already Executed");
executed = true;//看是否执行过,每一个Call只能执行一次
}
captureCallStackTrace();
eventListener.callStart(this);//回调请求执行事件监听器
try {
client.dispatcher().executed(this);//加入到Dispatcher对象的runningSyncCalls同步任务队列中
Response result = getResponseWithInterceptorChain();//阻塞,执行一系列拦截器,完成请求,返回结果
if (result == null) throw new IOException("Canceled");//返回结果为null的话,就是这个请求在后续的处理过程中被取消了。
return result;//返回结果
} catch (IOException e) {
eventListener.callFailed(this, e);//事件监听回调
throw e;
} finally {
client.dispatcher().finished(this);//完成当前请求,将任务从同步任务队列中删除。
}
}
过程简述:
-
判断是否已经能执行过,如果已经执行过,直接抛异常,停止请求;
-
回调事件监听callStart;
-
调用Dispatcher的executed方法,将任务添加到同步任务队列中;
-
阻塞,调用getResponseWithInterceptorChain方法,执行拦截器链,完成请求,返回结果
-
判断请求结果,看是否请求被取消了;
-
再次调用Dispatcher中的finished方法,将当前Call从同步任务队列中删除,当前请求Call完成。
这个过程中有Dispatcher的参与,看一下它的相关代码:
Dispatcher
public final class Dispatcher {
private int maxRequests = 64;//最大请求数量,包括同步请求和异步请求,从下面的三种队列中相加进行统计
private int maxRequestsPerHost = 5;//访问同一个主机的请求最大数量
private @Nullable Runnable idleCallback;//空闲时回调,空闲指的时正在执行同步和异步的Call个数为0的时候
/** Executes calls. Created lazily. */
private @Nullable ExecutorService executorService;//线程池,执行任务
/** Ready async calls in the order they'll be run. */
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();//准备被执行的异步Call-->AsyncCall
/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();//正在执行的异步Call-->AsyncCall
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();//正在执行的同步Call-->RealCall
public Dispatcher(ExecutorService executorService) {
this.executorService = executorService;
}
public Dispatcher() {
}
//创建线程池
public synchronized ExecutorService executorService() {
if (executorService == null) {
//线程池中核心线程为0,最大线程数可以为Integer.MAX_VALUE,空闲存活时间为60S
//即这个线程池的特点是,来一个请求可以创建一个新的线程。但是线程数也有限制,上面的maxRequests可以限制最大的线程数量不能超过64.
//响应速度快。
//空闲60S后会回收所有线程的资源,也可以节省资源。
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
//Realcall中的client.dispatcher().executed(this);执行到这
/** Used by {@code Call#execute} to signal it is in-flight. */
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);//将Call直接添加到同步任务队列中
}
/** Used by {@code AsyncCall#run} to signal completion. */
void finished(AsyncCall call) {
finished(runningAsyncCalls, call, true);
}
/** Used by {@code Call#execute} to signal completion. */
void finished(RealCall call) {
//第三个参数promoteCalls:同步请求时为false,异步为true。
finished(runningSyncCalls, call, false);
}
//calls异步和同步对应的任务队列
//call 正在进行的call
//promoteCalls 同步请求是为false 异步请求时为true
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;//正在执行的Call的数量
Runnable idleCallback;//空闲回调
synchronized (this) {
//删除当前Call
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
if (promoteCalls) promoteCalls();//同步请求不执行,异步请求执行
runningCallsCount = runningCallsCount();//统计正在执行的Call的数量,包括同步请求个异步请求;
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
}
可以看到,在同步请求的时候:
首先调用executed(RealCall call)方法,将RealCall对象添加到runningSyncCalls队列中;
其实也就是添加到队列中,后续对请求的执行,不会从同步队列中获取任务,而是直接对上述的RealCall进行操作。这里的队列其实就是为了多个任务的进度控制。
然后,任务执行完之后,执行finished方法,将当前任务从队列中删除。就可以了。