OkHttp系列四、OkHttp异步请求流程和源码分析

异步请求的前面三部步:创建OKHttp对象,创建Request对象,创建Call对象都是一样的,这里就不再累述。我们直接从call调用enqueue方法开始进行异步请求开始分析,enqueue方法源码如下:

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));
	}
}

参数executed和 captureCallStackTrace();eventListener.callStart(this);这两行代码的作用同前面的同步请求。这里不多说。我们直接看最后一行代码:

client.dispatcher().enqueue(new AsyncCall(responseCallback));

这里首先是系统把我们传进来的Callback对象封装成了一个AsyncCall对象,而AsyncCall则是RealCall类的一个final修饰的继承于Runnable的内部类本质上来说就是系统把我们传进去的Callback对象传递给了一个Runnable线程。client.dispatcher().enqueue()源码如下:

synchronized void enqueue(AsyncCall call) {
	if (runningAsyncCalls.size() < maxRequests && 
		runningCallsForHost(call) < maxRequestsPerHost) {
		runningAsyncCalls.add(call);
		executorService().execute(call);
	} else {
		readyAsyncCalls.add(call);
	}
}

这是一个加了synchronized同步锁的方法,它主要做了这几个事情:一是将call请求对象添加到Deque runningAsyncCalls异步队列里面去。二是当前正确执行的请求队列数量小于我们的最大请求阀值(maxRequests=64)的时候,且我们正在运行的主机请求数量小于我们设定的最大请求值(maxRequestsPerHost=5)得时候,发起请求,否则只是加入请求队列,等待执行。另外,executorService()是dispatcher里面的创建的一个可缓存的没有核心线程的线程池,线程池大小理论上没限制,但实际大小完全依赖于JVM。
executorService().execute(call)保证了异步请求发生在子线程里面。不会阻塞主线程。
AsyncCall的execute()方法如下:

protected void execute() {
	boolean signalledCallback = false;
	try {
		Response response = getResponseWithInterceptorChain();
		if (retryAndFollowUpInterceptor.isCanceled()) {
			signalledCallback = true;
			responseCallback.onFailure(RealCall.this, new IOException("Canceled"));/////////////核心重点代码
		} else {
			signalledCallback = true;
			responseCallback.onResponse(RealCall.this, response);/////////////核心重点代码
		}
	} catch (IOException e) {
		if (signalledCallback) {
		// Do not signal the callback twice!
		Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
	} else {
		eventListener.callFailed(RealCall.this, e);
		responseCallback.onFailure(RealCall.this, e);
	}
	} finally {
		client.dispatcher().finished(this);/////////////核心重点代码
	}
}

RealCall里面的的execute()方法才是真正的做数据请求的方法。
getResponseWithInterceptorChain()前面大致讲到了,他是一个拦截器链,实现了很多拦截器的功能。最核心的代码就是上面加粗的三行代码。

原创文章 118 获赞 149 访问量 9万+

猜你喜欢

转载自blog.csdn.net/haoyuegongzi/article/details/103001258