通过该篇文章大家可以了解到如下几点
1.首先通过一个简单的代码示例了解Call是什么
2.从源码的角度分析一下Call的定义
3.分析一下Call的实现类,从而真正了解Call
首先我们先以一段简短的代码为开头来了解一下Call在我们OkHttp中的作用.
OkHttpClient client = new OkHttpClient();
String run(String url) throws IOException {
Request request = new Request.Builder()
.url(url)
.build();
Call call = client.newCall(request);
try (Response response = call.execute()) {
return response.body().string();
}
}
从上面的代码中我们可以简单地看出,Call 的作用就是执行一个准备好的请求。
接下来我们从Call的定义中了解一下Call到底是什么,下面给出的是Call接口的源码。
public interface Call {
/**
**该方法返回的是原始的请求,也就是我们上面通过client.newCall中注入的Request。
**/
Request request();
/**
**立即执行该请求,并进入阻塞状态,直到请求处理得到响应或者发生error。
**/
Response execute() throws IOException;
/**
**异步执行请求,该方法不会被阻塞,在OkHttpClient中的调度器dispatcher定义了该方法请求何时被运行,正常情况下都是立马去执行的,除非目前正在执行其他的请求,在客户端将HTTP得到的响应(失败异常)会调用参数Callback 将其回调出去
**/
void enqueue(Callback responseCallback);
/**
**取消请求,如果请求已经执行结束了,则无法取消
**/
void cancel();
/**
**
请求是否已经执行,如果调用了execute()或者enqueue()方法,则返回true
**/
boolean isExecuted();
/**
**请求是否已取消
**/
boolean isCanceled();
interface Factory {
Call newCall(Request request);
}
}
从上面的代码中,我们可以了解到Call大致有以下几个功能:
- 获取原始请求
- 同步阻塞的方式执行请求
- 异步分阻塞的方式执行请求
- 在请求结束前可以取消请求
- 查看当前请求是否被执行
- 查看当前请求是否被取消
其实Call只有一个实现类RealCall,我们最上面的代码中通过call.newCall构造的Call就是我们的RealCall。
@Override public Call newCall(Request request) {
return new RealCall(this, request);
}
接下来我们通过它的部分源码了解一下RealCall。
final class RealCall implements Call {
private final OkHttpClient client;
private boolean executed;
volatile boolean canceled;
Request originalRequest;
/**
**Http执行引擎,也就是真正执行Http请求的类。
**/
HttpEngine engine;
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain(false);
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}
@Override public void enqueue(Callback responseCallback) {
enqueue(responseCallback, false);
}
void enqueue(Callback responseCallback, boolean forWebSocket) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));
}
@Override public void cancel() {
canceled = true;
if (engine != null) engine.cancel();
}
@Override public synchronized boolean isExecuted() {
return executed;
}
@Override public boolean isCanceled() {
return canceled;
}
首先看一下我们的execute方法,内部通过synchronized保证每个RealCall只能执行一次execute,而且内部通过dispatcher执行我们的请求,那接下来我们看一下Dispatcher的源码。
public final class Dispatcher {
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
/** Executes calls. Created lazily. */
private 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<>();
public Dispatcher(ExecutorService executorService) {
this.executorService = executorService;
}
从上面的源码可以看出,内部封装了一个线程池和三个队列,分别是准备好的异步Call队列和正在运行的异步Call队列和正在运行的同步Call队列。
那我们看看Dispatcher中对应于RealCall中的executed方法。
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
内部就是将对应的Call加入同步队列。
1: Response result = getResponseWithInterceptorChain(false);
2: private Response getResponseWithInterceptorChain(boolean forWebSocket) throws IOException {
Interceptor.Chain chain = new ApplicationInterceptorChain(0, originalRequest, forWebSocket);
return chain.proceed(originalRequest);
}
3: 通过执行引擎HttpEngine执行请求。
engine = new HttpEngine(client, request, false, false, forWebSocket, null, null, null);
接下来我们看一下Dispatcher中对应于RealCall中的enqueue方法。
void enqueue(Callback responseCallback, boolean forWebSocket) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));
}
该方法通过构造一份异步的Call,然后在Dispatcher中的线程池执行。
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
好了,到目前为止,大家已经了解了Call在OkHttp中所起到的作用。
网友评论