使用
val client = OkHttpClient.Builder().build()
val request = Request.Builder()
.url("https://www.baidu.com")
.build()
client.newCall(request).enqueue(object : okhttp3.Callback {
override fun onResponse(call: okhttp3.Call, response: okhttp3.Response) {
}
override fun onFailure(call: okhttp3.Call, e: IOException) {
}
})
分析
1. RealCall
通过创建的client的newRealCall创建一个RealCall对象,同时这个创建出的realCall对象也会吃有一个client的引用和外部创建的request对象,这个对象包括我们自己配置的属性像url之类
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
// Safely publish the Call instance to the EventListener.
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.transmitter = new Transmitter(client, call);
return call;
}
后面就会调用创建的这个call对象的enqueue方法,把callback对象传进来,用来在请求完成(或者失败)的时候通过这个对象把消息传出去
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.callStart();
//这里会把callback包进一个AsynCall对象中,这个类最后就就是继承的Runnable
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
这里可以看到把一个Runable传给了一个dispatcher的enqueue方法中,由此可以知道这里面一定会有thread去调用我们传进来的runable对象,执行它的run方法,实际上是走的execute方法
2. 切换线程
/** Executes calls. Created lazily. */
private @Nullable ExecutorService executorService;
/** Ready async calls in the order they'll be run. */
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
这几个就是dispatch类的变量,我们传来的的call对象最后被放进了readyAsyncCalls这个双端队列中等待线程调用
void enqueue(AsyncCall call) {
synchronized (this) {
readyAsyncCalls.add(call);
// Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
// the same host.
if (!call.get().forWebSocket) {
AsyncCall existingCall = findExistingCallWithHost(call.host());
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
}
}
promoteAndExecute();
}
紧接着就来到了最关键的方法
private boolean promoteAndExecute() {
assert (!Thread.holdsLock(this));
List<AsyncCall> executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this) {
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall asyncCall = i.next();
//判断是否超过了最大请求数量
if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
//判断是否超过了一个端口最大请求数量,一般是2个
if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.
i.remove();
asyncCall.callsPerHost().incrementAndGet();
executableCalls.add(asyncCall);
//把对象放进另一个队列中
runningAsyncCalls.add(asyncCall);
}
isRunning = runningCallsCount() > 0;
}
//遍历处理好的running队列,去执行它的executeOn方法
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
asyncCall.executeOn(executorService());
}
return isRunning;
}
切换线程
void executeOn(ExecutorService executorService) {
assert (!Thread.holdsLock(client.dispatcher()));
boolean success = false;
try {
//使用executorService来切换线程,这就实现了网络请求从主线程来到了子线程,完成后会通过callback把请求结果回调回去,这时候我们需要自己手动再切换回主线程去做一些页面刷新操作
executorService.execute(this);
success = true;
} catch (RejectedExecutionException e) {
InterruptedIOException ioException = new InterruptedIOException("executor rejected");
ioException.initCause(e);
transmitter.noMoreExchanges(ioException);
responseCallback.onFailure(RealCall.this, ioException);
} finally {
if (!success) {
client.dispatcher().finished(this); // This call is no longer running!
}
}
}
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;
}
okhttp自定义了一个线程池,这个线程池看起来和cachethreadPool差不多,都是可以存放无限的线程,但是我们网络请求其实不能无限创建,这时候的限制逻辑其实是放在前面的遍历方法中去做过滤,这里使用无限的写法也不会有问题
3. 实际进行网络请求
@Override protected void execute() {
boolean signalledCallback = false;
transmitter.timeoutEnter();
try {
//真正进行网络请求,连接建立,往sock写和读数据等都是这一行
Response response = getResponseWithInterceptorChain();
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);
}
} catch (Throwable t) {
cancel();
if (!signalledCallback) {
IOException canceledException = new IOException("canceled due to " + t);
canceledException.addSuppressed(t);
responseCallback.onFailure(RealCall.this, canceledException);
}
throw t;
} finally {
//注意这里进行了最后的工作,像前面我们遍历时候没有放进running队列中的请求,这时候再次去看一下是否可以再次请求
client.dispatcher().finished(this);
}
}
private <T> void finished(Deque<T> calls, T call) {
Runnable idleCallback;
synchronized (this) {
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
idleCallback = this.idleCallback;
}
boolean isRunning = promoteAndExecute();
if (!isRunning && idleCallback != null) {
idleCallback.run();
}
}