之前一直在使用volley作为网络请求模块,但发现volley已经过时(源码还是很值得反复品味的),现在基本是Retrofit和OkHttp的天下了,于是把OkHttp拿来学习一下。
首先,看一个OkHttp的简单示例:
Request.Builder builder = new Request.Builder().url(url).get();
Request okRequest = builder.build();
Call call = mOkHttpClient.newCall(okRequest);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
mHandler.post(new Runnable() {
@Override
public void run() {
listener.onFetchFinished(response.body().string());
}
});
}
});
该类框架都比较类似,创建一个请求及回调,然后加入请求队列,后面就由框架来进行任务调度,和结果回调。具体的细节,后面使用时再慢慢看,现在先探索一下OkHttp的主路线。
首先, 把请求加入到任务队列:
//okhttp3.RealCall.java
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
此方法就为避免单个请求多次添加,
// Dispatcher.java
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
/** Returns the number of running calls that share a host with {@code call}. */
private int runningCallsForHost(AsyncCall call) {
int result = 0;
for (AsyncCall c : runningAsyncCalls) {
if (c.host().equals(call.host())) result++;
}
return result;
}
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
这个方法比较有意思,很明显有两个任务队列,一个是正在执行的队列(runningAsyncCalls)和一个等待队列(readyAsyncCalls);不仅限制了最大并发请求的数量,还对同一个域名的并发请求做了限制,当然单个应用可能请求的域名都是一样的,所以这个就得看实际情况了。
当前并发请求数量小于限制时,就把请求直接丢到线程池中执行;否则就把请求加入到等待队列。在代码中搜索readyAsyncCalls,看看等待队列中的任务是什么时候被执行的。看到下面的方法:
// Dispatcher.java
private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
for (Iterator i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
搜索这个方法是在哪里被调用的:
可以看到,在任务结束、改变最大并发请求和改变域名最大并发请求时会调用该方法,这些肯定是在意料之中的。
接下来就跟踪一下任务是如何执行的,我们就从队列中的请求任务入手。
AsyncCall的继承关系如下:
abstract class NamedRunnable implements Runnable
final class AsyncCall extends NamedRunnable
/**
* Runnable implementation which always sets its thread name.
*/
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = Util.format(format, args);
}
@Override public final void run() {
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
任务的执行放在了execute()中执行。我们来看看AsyncCall的execute()方法:
@Override 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 {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
可以看出来,主要的内容是在getResponseWithInterceptorChain()里面,因为这个方法直接返回了Response,也就是请求结果。
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);
}
这个方法的主要内容是得到一个列表interceptors,从字面上看,这个列表是用于请求拦截。通过断点跟踪后发现,这个列表确实重要,并且顺序也是非常的重要,从下面的代码慢慢分析。
//RealInterceptorChain.java
@Override public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpStream, connection);
}
public Response proceed(Request request, StreamAllocation streamAllocation, HttpStream httpStream, Connection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
、、、
// Call the next interceptor in the chain.
//注意这里的index+1了
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpStream, connection, index + 1, request);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
、、、
return response;
}
省略一些异常情况处理后,很清晰的看到,从interceptors列表的第一项(index初始化为0)开始执行interceptor.intercept(next),并且参数是RealInterceptorChain链条的下一个节点。
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
streamAllocation = new StreamAllocation(
client.connectionPool(), createAddress(request.url()));
int followUpCount = 0;
Response priorResponse = null;
while (true) {
if (canceled) {
streamAllocation.release();
throw new IOException("Canceled");
}
Response response = null;
boolean releaseConnection = true;
try {
response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);
releaseConnection = false;
} catch (RouteException e) {
、、、
} finally {
// We're throwing an unchecked exception. Release any resources.
if (releaseConnection) {
streamAllocation.streamFailed(null);
streamAllocation.release();
}
}
// Attach the prior response if it exists. Such responses never have a body.
if (priorResponse != null) {
response = response.newBuilder()
.priorResponse(priorResponse.newBuilder().body(null).build())
.build();
}
Request followUp = followUpRequest(response);
if (followUp == null) {
if (!forWebSocket) {
streamAllocation.release();
}
return response;
}
closeQuietly(response.body());
、、、
request = followUp;
priorResponse = response;
} // end while
}
这个方法的主体是一个死循环,有两种方式退出循环:一个是throw new IOException(“Canceled”),另一个是return response。也就是说,当请求被取消,或者得到结果了就结束返回了。再看看response是什么时候被赋值的:
response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);
又回到刚才的proceed(request)里面了,而proceed(request)里面用到了index+1,也就是这时会使用interceptors列表中的第二个interceptor来进行intercept(next),酱紫看来,这是一个递归的过程。只有当进行到chain中的某一个节点,能够得response而不是继续向下传递时,递归开始反转退栈。
跟踪代码看到interceptor的顺序为RetryAndFollowUpInterceptor——>BridgeInterceptor——>CacheInterceptor——>ConnectInterceptor——>CallServerInterceptor. 至于为何需要这么几层,还不是很清楚,还需要继续学习。
至此,okhttp的请求主流程基本介绍完毕,后面还有大量的东西需要去学习。