OkHttp 4是用kotlin写的,我这里使用的是3.9.1版本。
OkHttp的使用,发送同步请求
OkHttpClient client = new OkHttpClient();
// 第二步,创建请求
Request request = new Request.Builder().url("https://www.google.com").build(); // 创建GET请求
/* RequestBody body = RequestBody.create(JSON, params);
Request request = new Request.Builder().url(url).post(body).build(); */ // 创建POST请求
// 第三步,发送请求,获取Response
Response response = client.newCall(request).execute();
/* client.newCall(request).enqueue(Callback) */ // 异步请求,callback用于接收response
复制代码
new OkHttpClient(),最重要的作用就是创建Dispatcher,这是用于分发请求是由哪个线程处理的。
new Request.Builder().url()…build(),这是建造者模式的写法,创建了请求对象,传入最重要的参数url。
第三步发送请求细,分为两步,第1步,将request包装为Call。
下面的newCall()方法的代码实例:
class OkHttpClient {
public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
}
复制代码
上面,这个方法是OkHttpClient的方法,所以这里传入的this,是OkHttpClient本身。
第2步,调用RealCall.execute()发送请求,具体如下:
class RealCall implements Call {
public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.timeoutEnter();
transmitter.callStart();
try {
client.dispatcher().executed(this);
return getResponseWithInterceptorChain();
} finally {
client.dispatcher().finished(this);
}
}
}
复制代码
如上,client.dispatcher().executed(this),这里this是RealCall,由于RealCall封装了Request,所以可以执行行请求。// TODO,synchronized和finished都值得一讲
在构建RealCall对象时,传入了OkHttpClient对象,就是这里的client。client.dispatcher()即Dispatcher对象。
Diapathcer执行的过程,只是将请求添加到运行运行队列,如下。
class Dispatcher {
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
}
复制代码
真正发送请求,获得Response是getResponseWithInterceptorChain(),这个后面讲解(一号坑)。
使用OkHttp发送异步请求
前面的client和request创建时相同的,区别在于发送的时候,调用enqueue(),且需要传入Callback用于接收Response。
client.newCall(request).enqueue(Callback)
异步请求与同步请求类似,差异是第三步使用的enqueue()方法。下面是enqueue()的源码:
class RealCall implements Call {
public Response execute() throws IOException { // execute,方便与enqueue对比
...
client.dispatcher().executed(this);
return getResponseWithInterceptorChain();
}
public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.callStart();
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
}
复制代码
如上,client.dispatcher().enqueue(new AsyncCall(responseCallback)),异步请求是会创建一个AsyncCall,之后再将AsyncCall入列。
下面是添加过程的源码。有一点要注意的是,AsyncCall并没有跟Request关联起来,在执行异步请求时如何拿到请求url,这里挖一个坑后面讲(二号坑)。
class Diapathcer {
void enqueue(AsyncCall call) {
synchronized (this) {
readyAsyncCalls.add(call);
if (!call.get().forWebSocket) {
AsyncCall existingCall = findExistingCallWithHost(call.host());
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
}
}
promoteAndExecute();
}
}
复制代码
如上,enqueue()的执行过程,是将AsyncCall添加到异步等待队列readyAsyncCalls,然后调用promoteAndExecute(),如下是源码。
class Diapathcer {
private boolean promoteAndExecute() {
assert (!Thread.holdsLock(this));
List<AsyncCall> executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this) {
/* 将AsyncTask从readyAsyncCalls遍历,添加到临时队列和异步运行队列, */
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall asyncCall = i.next();
if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.
i.remove();
asyncCall.callsPerHost().incrementAndGet();
executableCalls.add(asyncCall);
runningAsyncCalls.add(asyncCall);
}
isRunning = runningCallsCount() > 0;
}
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
// 执行异步请求
asyncCall.executeOn(executorService());
}
return isRunning;
}
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;
}
}
复制代码
AsyncCall是一个线程(class AsyncCall extends NamedRunnable),它并不是RealCall、或者Call接口的子类。
如上,asyncCall.executeOn(executorService())
,executorService()创建了一个无限大Integer.MAX的线程池,用于执行异步请求运行。这个线程池作为AsyncCall.executeOn()的入参,后面AsyncCall就是使用该线程池让自己被执行起来,核心代码:executorService.execute(this)
,这里this是AsyncCall,它是个线程,使用线程池来运行AsyncCall线程,这样就做到了异步请求。
AsyncCall被线程池执行后,下面就应该看AsyncCall(的父类)的run()方法了。其内部执行了抽象方法execute(),所以在AsyncCall找到具体实现,如下:
class AsyncCall extends NamedRunnable {
protected void execute() {
...
try {
Response response = getResponseWithInterceptorChain();
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
} finally {
client.dispatcher().finished(this);
}
}
}
复制代码
通过getResponseWithInterceptorChain()获取到请求结果,然后通过回调将response传递给请求调用者。
终于讲到最核心的getResponseWithInterceptorChain(),这也是填坑一号坑。这是责任链的写法,具体待追加。// TODO
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(new RetryAndFollowUpInterceptor(client));
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
// 注意下面的originalRequest,这就是请求。填二号坑,虽然AsyncCall不直接持有request,但AsyncCall是RealCall的内部类,而RealCall是持有request的,所以AsyncCall是在这里,拿到请求的。
Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
boolean calledNoMoreExchanges = false;
try {
Response response = chain.proceed(originalRequest);
if (transmitter.isCanceled()) {
closeQuietly(response);
throw new IOException("Canceled");
}
return response;
} catch (IOException e) {
calledNoMoreExchanges = true;
throw transmitter.noMoreExchanges(e);
} finally {
if (!calledNoMoreExchanges) {
transmitter.noMoreExchanges(null);
}
}
}
复制代码