我们开始学习 OkHttp 都具体帮我们做了哪些操作,大概会分三小节来学习它:
OkHttp 的使用比较简单,发起一个异步请求的代码如下:
private void testOkHttp() {
OkHttpClient okHttpClient = getOkHttpClient(); //构造 OkHttpClient
Request request = new Request.Builder()
.get() //Method GET
.url("www.baidu.com")
.build(); //构造请求信息
okHttpClient.newCall(request)
.enqueue(new Callback() { //发起异步请求
@Override
public void onResponse(final Call call, final Response response) throws IOException {
//成功拿到响应
int code = response.code();
ResponseBody body = response.body();
String string = body.string();
}
@Override
public void onFailure(final Call call, final IOException e) {
e.printStackTrace();
}
});
}
可以看到,使用 OkHttp 发起一个异步请求主要三步:
OkHttpClient Request 那么在这简单的代码背后, OkHttp 都做了什么呢?请求是如何被执行的呢?响应是如何拿到的呢?
我们先看一下 请求的提交流程 。
我们查看一下 okHttpClient.newCall(request) 方法的源码:
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
newCall(Request) 方法调用了 RealCall.newRealCall() 方法:
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.eventListener = client.eventListenerFactory().create(call);
return call;
}
这个 RealCall.newRealCall()` 方法创建了一个新的 RealCall 对象,这个 RealCall 是 okhttp3.Call`` 接口的一个实现。
okhttp3.Call 表示一个等待执行的请求,它只能被执行一次,定义了这些方法:
public interface Call extends Cloneable {
//返回这个请求关联的 Request 对象
Request request();
//立即执行请求,阻塞等待拿到响应
Response execute() throws IOException;
//请求入队,异步执行
void enqueue(Callback responseCallback);
//取消一个请求
void cancel();
boolean isExecuted();
boolean isCanceled();
Call clone();
interface Factory {
Call newCall(Request request);
}
}
可以看到,我们前面发起异步请求的 enqueue() 方法是定义在 Call 中的。
okHttpClient.newCall(request)
.enqueue(new Callback() { ...}); //原来就是 Call 的方法
在 OkHttp 中, Call 的唯一实现就是 RealCall ,它表示一个准备好被执行的请求。和 Request 不同在于,它还提供了发起请求、取消等方法。
在 Retrofit 中也定义了一个 Call 接口,不过它俩层次不一样,相较于 OkHttp.Call , Retrofit.Call 增加了更多信息,这个我们后面介绍。
拿到 OkHttp.Call 的实例、 RealCall 对象后,我们调用了它的 enqueue() 方法:
//RealCall.enqueue()
@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)); ,它做了两件事:
AsyncCall 对象 Dispatcher.enqueue() 方法将请求入队 先看下 AsyncCall 是何方神圣:
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
String host() { //用于标识这个请求
return originalRequest.url().host();
}
Request request() {
return originalRequest;
}
RealCall get() {
return RealCall.this;
}
@Override protected void execute() {
//...
}
}
可以看到, AsyncCall 就是一个 Runnable,用于异步执行任务。
接着看 client.dispatcher() 方法,它返回一个调度器 Dispatcher ,这是 OkHttp 中比较核心的一个类:
public final class Dispatcher {
private int maxRequests = 64; //同时最多发起 64 个请求
private int maxRequestsPerHost = 5; //同一 host 最多发起 5 个请求
private @Nullable Runnable idleCallback;
private @Nullable ExecutorService executorService; //将会异步创建的线程池
//等待被执行的异步请求队列
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
//正在运行的异步请求队列(其中也包括取消后没有完成的请求)
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
//正在运行的同步请求队列
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
public Dispatcher(ExecutorService executorService) {
this.executorService = executorService;
}
public Dispatcher() {
}
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
//...
}
我们可以得到比较关键的信息如下:
OkHttpClient 中一般只有一个 Dispatcher ,因此一个 OkHttpClient 能发起的最多请求就是 Dispatcher 中定义的 64 个 Dispatcher 中用三个队列保存同步、异步请求 SynchronousQueue ,因此有请求时会不断创建新线程 然后回到我们之前调用的 Dispatcher.enqueue() 方法:
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
可以看到,调度器在收到一个异步请求后,会先判断当前正在运行的异步请求是否超过默认的 64 个、同一 host 的请求是否小于默认的 5,是的话就开始执行;否则加入等待执行的队列中。
前面我们介绍了 AsyncCall 是一个 NamedRunnable ,等它被执行时会调用它的 run() 方法,这个方法调用了 execute() 方法。
public abstract class NamedRunnable implements Runnable {
//...
@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();
}
到这里我们了解了 一个请求从提交到执行背后所经历的 ,用一张图小结一下:
一个异步请求在发起到执行要经历这么几个状态: