OKHttp 基本使用,在上一篇我们已经介绍过OKHTTP深入浅出(二)----基本用法_王胖子总叫我减肥的博客-CSDN博客
之前我们介绍过OKHttp 的OKHttpClient对象和Request对象都是通过建造者模式构建的,首先要理解什么是建造者模式。仿照OKHttpClient的源码,写一个简单的建造模式
public class House {
private double height;
private double width;
private String color;
public House(Builder builder) {
this.color = builder.color;
this.height = builder.height;
this.width = builder.width;
}
public static final class Builder {
double height;
double width;
String color;
public Builder() {
this.height = 100;
this.width = 100;
this.color = "red";
}
public Builder setHeight(double height) {
this.height = height;
return this;
}
public Builder setWidth(double width) {
this.width = width;
return this;
}
public Builder setColor(String color) {
this.color = color;
return this;
}
public House build() {
return new House(this);
}
}
}
建造者模式,创建一个house类,属性有height、width、color,在house里面有一个final修饰的静态内部类Builder,在该类中,初始化了3个属性的默认值。同时也可以自己定义属性的值,定义属性值之后,注意返回的是Builder对象;最后在该类中,定义了一个build()方法,其中的this代表用builder,来创建真正的House对象。这就是构建模式。理解了构建模式,能够帮助我们理解OKHttp的源码。
我们使用GET请求访问网路如下:
//1.构建okHttpClient对象
OkHttpClient okHttpClient = new OkHttpClient();
//2.构建request请求对象
Request request = new Request.Builder().url("www.baidu.com").get().build();
//3.生成call对象
Call call = okHttpClient.newCall(request);
//4.异步请求
call.enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
Log.e(TAG,"okhttp get enqueue:" + response.body().string());
ResponseBody body = response.body();
String string = body.string();
byte[] bytes = body.bytes();
InputStream inputStream = body.byteStream();
}
1、OKHttpClinet对象的创建
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
final Dispatcher dispatcher;
final @Nullable Proxy proxy;
final List<Protocol> protocols;
final List<ConnectionSpec> connectionSpecs;
final List<Interceptor> interceptors;
....
public OkHttpClient() {
this(new Builder());
}
OkHttpClient(Builder builder) {
this.dispatcher = builder.dispatcher;
this.proxy = builder.proxy;
this.protocols = builder.protocols;
this.connectionSpecs = builder.connectionSpecs;
this.interceptors = Util.immutableList(builder.interceptors);
....
}
......
public static final class Builder {
Dispatcher dispatcher;
@Nullable Proxy proxy;
List<Protocol> protocols;
List<ConnectionSpec> connectionSpecs;
final List<Interceptor> interceptors = new ArrayList<>();
......
public Builder() { // 默认的配置属性
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
proxySelector = ProxySelector.getDefault();
if (proxySelector == null) {
proxySelector = new NullProxySelector();
}
.....
}
//可自定义的属性
public Builder connectTimeout(long timeout, TimeUnit unit) {
connectTimeout = checkDuration("timeout", timeout, unit);
return this;
}
.....
}
细看一下,发现OKHttpClient 的构建方式和我们上面说的House简直一样,因此不难理解。
2、Request对象的创建,使用的也是构建者模式
public final class Request {
final HttpUrl url;
final String method;
final Headers headers;
final @Nullable RequestBody body;
final Map<Class<?>, Object> tags;
private volatile @Nullable CacheControl cacheControl; // Lazily initialized.
Request(Builder builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = builder.headers.build();
this.body = builder.body;
this.tags = Util.immutableMap(builder.tags);
}
public HttpUrl url() {
return url;
}
public String method() {
return method;
}
...
public static class Builder {
@Nullable HttpUrl url;
String method;
Headers.Builder headers;
@Nullable RequestBody body;
/** A mutable map of tags, or an immutable empty map if we don't have any. */
Map<Class<?>, Object> tags = Collections.emptyMap();
public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}
Builder(Request request) {
this.url = request.url;
this.method = request.method;
this.body = request.body;
this.tags = request.tags.isEmpty()
? Collections.emptyMap()
: new LinkedHashMap<>(request.tags);
this.headers = request.headers.newBuilder();
}
public Builder url(HttpUrl url) {
if (url == null) throw new NullPointerException("url == null");
this.url = url;
return this;
}
public Builder url(String url) {
if (url == null) throw new NullPointerException("url == null");
// Silently replace web socket URLs with HTTP URLs.
if (url.regionMatches(true, 0, "ws:", 0, 3)) {
url = "http:" + url.substring(3);
} else if (url.regionMatches(true, 0, "wss:", 0, 4)) {
url = "https:" + url.substring(4);
}
return url(HttpUrl.get(url));
}
......
3、 接着查看OKHTTP 的newCall()方法
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
可以看到,其实OKHttpClient的newCall()方法实际上调用的是RealCall的newRealCall()方法。明白了,Call
是一个接口,而RealCall
实现了这个接口,所以返回new RealCall()
给call
对象当然是没问题的。
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
// Safely publish the Call instance to the EventListener.
RealCall call = new RealCall(client, originalRequest, forWebSocket);//1
call.transmitter = new Transmitter(client, call);//2
return call;
}
注释1处,来看一下调用的RealCall的构造方法,
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
}
通过OkHttpClient、Request、forWebSocket参数,创建了一个RealCall实例。
在回头看一下,RealCall的newRealCall()方法中的注释2处,new transmitter(),transmitter翻译为发射器,是应用层和网络层之间的桥梁,在真正进行连接、发出请求、接收响应的时候起到重要的作用。
public Transmitter(OkHttpClient client, Call call) {
this.client = client;
this.connectionPool = Internal.instance.realConnectionPool(client.connectionPool());
this.call = call;
this.eventListener = client.eventListenerFactory().create(call);
this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS);
}
可以看到call.transmitter持有了OkHttpClient、连接池、call对象、监听事件eventListener、timeout。
在看一下RealCall的实现类Call。
// 已准备要执行的请求。由于表示单个请求/响应对(流),因此无法执行两次
public interface Call extends Cloneable {
...
//同步请求,会阻塞
Response execute() throws IOException;
//异步请求
void enqueue(Callback responseCallback);
//取消请求,已经完成的不能取消。
void cancel();
boolean isExecuted();
boolean isCanceled();
Timeout timeout();
...
interface Factory {
Call newCall(Request request);
}
}
总结一下:OKHTTP 的newCall()方法,其实调用的是RealCall的newRealCall()方法,在RealCall的newRealCall()方法中主要做了两件事,第一件通过OKhttpClient、Request、forWebSocket参数构建了RealCall对象;第二件通过new Transmitter(client, call)为构建的RealCall对象的transmitter对象赋值。
4、请求的流程
call的请求分为同步请求和异步请求
4.1同步请求
call.execute()方法,由于call的真正实现是RealCall。因此会调用RealCall的execute()方法。
@Override public Response execute() throws IOException {
synchronized (this) { //1
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.timeoutEnter();//2
transmitter.callStart();//3
try {
client.dispatcher().executed(this);//4
return getResponseWithInterceptorChain();//5
} finally {
client.dispatcher().finished(this);//6
}
}
注释1处,表明了如果请求call只会执行一次的原因。注释2处,发射器开始超时计时;注释3,回调请求监听器的请求开始;注释4,调用了dispatch(调度器)的executed()方法,将请求放入一个双端队列runningSyncCalls中,表示正在执行的同步请求。
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
看看这份runningSyncCalls
的声明:
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
这个runningSyncCalls
是一个队列,从其源代码的注释我们可以得知这个runningSyncCalls的作用是存储当前OkHttpClient
正在执行的同步请求
注释5,真正请求返回结果的地方,getResponseWithInterceptorChain() ,方法的返回值要求是Response对象,因此getResponseWithInterceptorChain() 返回就是Response对象、
注释6,client.dispatcher().finished(this); 请求结束无论如何都会走的地方,此处的this传入的是call请求,会去调用dispatch的finished()方法。
void finished(RealCall call) {
finished(runningSyncCalls, call);
}
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();
}
}
client.dispatcher().finished(this)调用了dispatcher().finished(this)方法并将自身(call)传递了进去,在finished(RealCall call)方法中又调用了finished(Deque<T> calls, T call)方法,传入了runningSyncCalls和我们当前的call对象,还记得这个runningSyncCalls在哪里出现过吗?对的,它在dispater.excuted()方法中出现过,当时的操作是将当前call对象加入到这个runningSyncCalls队列中,那么现在请求结束了,就将当前的call对象移除。
这里注重分析一下getResponseWithInterceptorChain()方法。
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));
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); //1
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);
}
}
}
首先,new
了一个interceptors 应用拦截器集合,将
应用拦截器(用户配置)client.interceptors()、重试跟进拦截器RetryAndFollowUpInterceptor、桥拦截器BridgeInterceptor、缓存拦截器CacheInterceptor、连接拦截器ConnectInterceptor、网络拦截器(外部配置)client.networkInterceptors()、请求服务拦截器CallServerInterceptor,添加到集合中。
然后执行
Interceptor.Chain chain = new RealInterceptorChain(interceptors,
transmitter, null, 0,originalRequest,
this, client.connectTimeoutMillis(),
client.readTimeoutMillis(),
client.writeTimeoutMillis());
看一下RealInterceptorChain的构造方法
public RealInterceptorChain(List<Interceptor> interceptors, Transmitter transmitter,
@Nullable Exchange exchange, int index, Request request, Call call,
int connectTimeout, int readTimeout, int writeTimeout) {
this.interceptors = interceptors;
this.transmitter = transmitter;
this.exchange = exchange;
this.index = index;
this.request = request;
this.call = call;
this.connectTimeout = connectTimeout;
this.readTimeout = readTimeout;
this.writeTimeout = writeTimeout;
}
主要是初始化了一个RealInterceptorChain
类的对象,注意一下传入的第1个参数(interceptors
)和第4个参数(index
),分别传入的是我们刚才构成的拦截器集合以及0,一会我们会用到。
在getResponseWithInterceptorChain()方法的注释1处,Response response = chain.proceed(originalRequest);可以看到,真正返回的response
就是从这里的 chain.proceed(originalRequest)
方法返回的,当前这个chain
是RealInterceptorChain
类的对象,所以我们来看看RealInterceptorChain.proceed()
方法中做了什么
@Override public Response proceed(Request request) throws IOException {
return proceed(request, transmitter, exchange);
}
在跟进看一下,
public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
// If we already have a stream, confirm that the incoming request will use it.
if (this.exchange != null && !this.exchange.connection().supportsUrl(request.url())) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must retain the same host and port");
}
// If we already have a stream, confirm that this is the only call to chain.proceed().
if (this.exchange != null && calls > 1) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must call proceed() exactly once");
}
// Call the next interceptor in the chain.
//1
RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
// Confirm that the next interceptor made its required call to chain.proceed().
if (exchange != null && index + 1 < interceptors.size() && next.calls != 1) {
throw new IllegalStateException("network interceptor " + interceptor
+ " must call proceed() exactly once");
}
// Confirm that the intercepted response isn't null.
if (response == null) {
throw new NullPointerException("interceptor " + interceptor + " returned null");
}
if (response.body() == null) {
throw new IllegalStateException(
"interceptor " + interceptor + " returned a response with no body");
}
return response;
}
首先检查了一下index
是否超出了interceptors
的size
,还记得index
和interceptors
是什么吗?对的,就是我们在getResponseWithInterceptorChain()
源码传入的0和我们初始化的拦截器集合,
注释1处又初始化了一个RealInterceptorchain()对象,这个那这里初始化的这个RealInterceptorchain对象和之前RealInterceptorChain
有什么区别呢?
可以发现,只有一个参数不一样,就是index参数,现在的RealInterceptorchain传入的index参数是之前的RealInterceptorchain的index +1,然后下一行通过index拿到了interceptors中的元素interceptor(第一个拦截器),这也是proceed()方法的开头为什么先检测index和interceptors.size()大小关系的原因,就是为了防止这发生越界异常。拿到interceptor对象之后,下一行执行了interceptor.intercept(next)并返回了response,而最后也是将这个response最终作为当前proceed()方法的返回值,这时候我们就有必要深入一下interceptor.intercept(next)的源码了,我们尝试跟踪源码,会发现这个Interceptor其实是一个接口:
看一下这个接口的实现类。
我们看到了5个拦截器类,由于当前interceptor是通过interceptors.get(index)拿到的,而index当前传入的值为0,所以第一次执行的应该是第一个加入拦截器集合的那个拦截器类的intercept()方法,这里我们先不考虑用户自添加的拦截器,那么第一个拦截器就应该是RetryAndFollowUpInterceptor拦截器,我们来看看它的intercept()方法:
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
RealInterceptorChain realChain = (RealInterceptorChain) chain;//1
Transmitter transmitter = realChain.transmitter();
.......
}
Response response;
boolean success = false;
try {
response = realChain.proceed(request, transmitter, null);//2
success = true;
} catch (RouteException e) {
.....
注释1,将当前传入的chain转换成RealInterceptorChain对象;注释2,执行了realChain.process( request, transmitter, null)并且返回了Response。其中这个realChain就是我们当前调用的intercept()方法传入的chain参数。
RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
即由interceptors
和index 1
构建的新的RealInterceptorChain
,所以整个逻辑就是:
因此整个逻辑就是:
可以发现,整个拦截器集合构成了一个链式结构,当前拦截器执行完对应的拦截方法后激活下一个拦截器开始工作,直到最后一个拦截器,这也告诉我们如果要添加自定义的拦截器,则必须在重写intercept(Chain chain)方法时返回chain.proceed(),否则责任链就会断链,自然不会成功地发起网络请求。
注意由于CallServerInterceptor这个拦截器是最后一个拦截器,所以它的intercept方法中没有像之前的拦截器那样执行next.proceed(),而是直接使用传入的Chain chain参数直接发起了网络请求并返回Response。
总结一下同步请求的流程:
- Realcall.execute()发起同步网络请求。
- 利用execute标志位判断是否当前的call对象已经执行过了,若执行就抛出异常。
- 调用client.dispatcher.excuted(),将当前的call对象加入到runningSynccalls队列。
- 调用getResponseWithInterceptorChain()方法,内部试用责任链模式依次执行拦截器中的拦截器,最终发起网络请求,返回Response、
- 调用Client.dispatch.finished(),将当前call对象从runningSynccalls队列移除。
- 返回Response对象
4.2 异步请求
异步请求使用call.enqueue()方法
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
同理调用的也是RealCall的enqueue()方法。
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {// 1
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.callStart(); //2
client.dispatcher().enqueue(new AsyncCall(responseCallback));//3
}
注释1,异步请求enqueue也只能请求一次。注释2,回调请求监听器的请求开始。注释3,调用Dispatcher的enqueue方法,参数接受的是AsyncCall,AsyncCall继承NamedRunnable,NamedRunnable实现自Runnable,即AsyncCall就是个Runnable,可以想到它是会在线程或线程池执行run方法的。run方法在AsyncCall没看到啊,实际是在NamedRunnable中:
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
private volatile AtomicInteger callsPerHost = new AtomicInteger(0);
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
.....
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = Util.format(format, args);
}
@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();
}
回头在看一下注释3中的dispatcher的enqueue()方法,
void enqueue(AsyncCall call) {
synchronized (this) {
readyAsyncCalls.add(call);// 1
// 2
if (!call.get().forWebSocket) {
AsyncCall existingCall = findExistingCallWithHost(call.host());//3
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);//4
}
}
promoteAndExecute(); //5
}
注释1处。将请求放入等待队列。注释2,判断请求call是否是有相同的host(通过findExistingCallWithHost()方法)
@Nullable private AsyncCall findExistingCallWithHost(String host) {
for (AsyncCall existingCall : runningAsyncCalls) {
if (existingCall.host().equals(host)) return existingCall;
}
for (AsyncCall existingCall : readyAsyncCalls) {
if (existingCall.host().equals(host)) return existingCall;
}
return null;
}
从运行队列runningAsyncCalls和的等待队列readyAsyncCalls寻找到相同的host请求。
注释4,找到的相同的host请求后,将callsPerHost重用给当前请求。
void reuseCallsPerHostFrom(AsyncCall other) {
this.callsPerHost = other.callsPerHost;
}
就是对call对象的callsPerHost进行了更新,注意这里是直接使用了=对this.callsPerHost进行了赋值,而且在java中参数默认传递的是引用,所以当前callsPerHost和findExistingCallWithHost()中返回的那个AsyncCall对象的callsPerHost是同一个引用,那么再延伸一下,所有host相同的AsyncCall对象中的callsPerHost都是同一个引用,即如果改变其中一个AsyncCall对象的callsPerHost值,其他的所有AsyncCall对象的 callsPerHost的值也会随之改变,下面我们会看到作者巧妙地利用了这一点更新了所有host相同的 AsyncCall对象的callsPerHost值,实在是非常优秀。 这个callPerHost的声明如下,即初始值为0。
private volatile AtomicInteger callsPerHost = new AtomicInteger(0);
注释5,在同步请求中finished()方法中就调用了promoteAndExecute()方法,在这里异步请求中又一次调用了该方法,这个方法到底做了什么事呢?
private boolean promoteAndExecute() {
assert (!Thread.holdsLock(this));
List<AsyncCall> executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this) {
//1
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall asyncCall = i.next();
if (runningAsyncCalls.size() >= maxRequests) break; // 2.
if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // 3
i.remove(); //4
asyncCall.callsPerHost().incrementAndGet(); //5
executableCalls.add(asyncCall); //6
runningAsyncCalls.add(asyncCall); //7
}
isRunning = runningCallsCount() > 0;
}
//8
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
asyncCall.executeOn(executorService());
}
return isRunning;
}
这个方法为调度的核心方法:注释1,遍历了readyAsyncCalls
这个队列,对于readyAsyncCalls
中的每一个被遍历的当前AsyncCall
对象,
注释2,会首先判断runningAsyncCalls
这个队列的长度是否大于了maxRequests
,这个maxRequests
默认是64,意思就是说要求当前正在执行的网络请求不能超过64个(为了节约资源考虑),如果大于就直接返回。
注释3,判断asyncCall.callsPerHost().get()是否大于maxRequestsPerHost,maxRequestsPerHost的值默认为5,上面我们说到callsPerHost的初始为0,那么asyncCall.callsPerHost().get()初始应该是小于maxRequestsPerHost的,这里这个判断的意思就是当前正在执行的所有的请求中,与asyncCall对应的主机(host)相同请求的数量不能超过maxRequestsPerHost也就是5个,如果满足条件即同一个host的请求不超过5个。
注释4,首先将当前AsyncCall
对象从readyAsyncCalls
中移除。
注释5,就是将callsPerHost的值增1,上面提到,所有host相同的AsyncCall对象中的callsPerHost都是同一个引用,所以这里对当前这个callsPerHost的值增1实际上是更新了readyAsyncCalls中的所有AsyncCall对象中的callsPerHost的值,这样callsPerHost这个属性值就能够表示请求host与当前host相同的请求数量。
注释6,将当前AsyncCall加入到
executableCalls(可执行请求队列中),执行所有executableCalls
中的请求
注释7,将当前AsyncCall加入运行队列
runningAsyncCalls,表示请求正在运行。
注释8,主要是对executableCalls
进行了遍历,对于executableCalls
中的每一个AsyncCall
对象,执行asyncCall.executeOn()
方法,传入了一个executorService()
,首先看executorService()
的源码:
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;
}
这里使用单例模式返回了一个线程池的对象,线程池的核心线程数为0,最大线程数为Integer.MAX_VALUE(不限制),这是将线程池的最大线程数设置为Integer.MAX_VALUE的原因是:在Dispatcher中默认使用了maxRequest控制了同时并发的最大请求数,因此这里就不用加以控制了,然后设置了最大线程的最大存活时间为60S,就是说当前线程任务执行完毕之后,60S之内不会被销毁,如果此时有其他网络请求的任务,就不用新建线程,可以之前复用当前的线程。
在看一下asyncCall.executeOn()
方法,
void executeOn(ExecutorService executorService) {
assert (!Thread.holdsLock(client.dispatcher()));
boolean success = false;
try {
executorService.execute(this); //1
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!
}
}
}
尝试将此asyncCall
调用加入 executorService。 如果执行程序已通过报告调用失败而关闭,这将尝试进行清理。
注释1,是该方法的核心步骤,主要调用线程池executorService的execute()方法来执行当前asyncCall,之前说过asyncCall是实现了Runnable接口的。
final class AsyncCall extends NamedRunnable
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = Util.format(format, args);
}
@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();
}
NamedRunnable实现了Runnable接口,其run()方法主要是调用了抽象方法execute()方法,而execute()抽象方法会被asyncCall实现。
所以,AsyncCall
类的run()
方法实际上执行的是其execute()
中的内容:
@Override protected void execute() {
boolean signalledCallback = false;
transmitter.timeoutEnter();
try {
Response response = getResponseWithInterceptorChain();//1
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 {
client.dispatcher().finished(this);//2
}
}
可以看到,execute()方法中发起了真正的网络请求,核心方法是注释1,getResponseWithInterceptorChain(),这其作用是发起网络请求,返回Response,注意这里使用了try...catch语句块对异常进行了捕捉,如果发生异常,则调用responseCallback.onFailure(RealCall.this, e),而这个responseCallback就是我们发起异步请求时传入的那个CallBack对象,所以就是在这里回调的onFailure()方法。如果请求成功,则调用responseCallback.onResponse(RealCall.this, response)即我们的onResponse()回调方法。
那么由于当前execute()方法是在Runnable接口的run()方法中被调用的,而asyncCall又被传入了executorService.execute()中,所以当前execute()方法会在线程池中被执行,即onFailure()和onResponse()这两个回调方法会在子线程被调用,这也说明了我们不能再RealCall.enqueue()方法的回调中直接更新UI,因为其回调方法都是在子线程被调用的。
注释2,client.dispatcher().finished(this),this指的的asyncCall,
void finished(AsyncCall call) {
call.callsPerHost().decrementAndGet();
finished(runningAsyncCalls, call);
}
其中call.callsPerHost().decrementAndGet(),将AsyncCall的callsPerHost的值减去1,因为当前的AsyncCall已经结束了,那么就应该将与当前AsyncCall具有相同的host的请求数量减去1,然后调用了
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();
}
}
主要将当前的AsyncCall从runningAsyncCalls
中移除。
总结一下异步请求的流程:
- 调用call.enqueue(Callback callback),传入call回调。
- 将当前的call对象转化为AsyncCall对象,调用Client.dispatch.enqueue(),调用OKHttpClinet的dispatch对象的enqueue()方法。
- 将当前的AsyncCall对象加入readyAsyncCalls队列。
- 遍历readyAsyncCalls,将符合条件的AsyncCall移除并加入到executableCalls和 runningAsyncCalls集合。
- 遍历executable集合,执行每一个AsyncCall对象的execute()方法,传入线程池。
- 在线程池中发起当前的AsyncCall的网络请求。
- 回调成功或者失败对应的回调方法。
- 将当前的AsyncCall对象从
runningAsyncCalls
中移除。