我们开始学习 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(); }
到这里我们了解了 一个请求从提交到执行背后所经历的 ,用一张图小结一下:
一个异步请求在发起到执行要经历这么几个状态: