本文使用的OkHttp版本 ↓
implementation 'com.squareup.okhttp3:okhttp:3.10.0'
关于OkHttp,大家应该都不陌生了,这里就不多介绍,从我们最常见的使用场景开始
1,同步
//第一种方式
OkHttpClient okHttpClient = new OkHttpClient();
//第二种方式
//OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
Request request = new Request.Builder()
.url("https://www.baidu.com/")
.get()
.build();
try {
Response response = okHttpClient.newCall(request).execute();
Log.d(TAG, "response: " + response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
获取OkHttp实例
首先我们要获取OkHttpClient的实例,这里有两种
一种是直接通过无参构造方法获取,一种是通过构建者模式获取
让我先来看看无参构造
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);
this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
this.eventListenerFactory = builder.eventListenerFactory;
this.proxySelector = builder.proxySelector;
this.cookieJar = builder.cookieJar;
this.cache = builder.cache;
this.internalCache = builder.internalCache;
this.socketFactory = builder.socketFactory;
···
}
内部调用了Builder为入参的构造方法,传入了一个Builder实例,这个Builder是OkHttpClient的内部类,
Builder在无参构造方法中,获取了OkHttpClient需要的一些实例和默认配置,最后依次赋给了OkHttpClient,
如果需要进行额外的配置,我们可以直接操作这个OkHttpClient
public static final class Builder {
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
proxySelector = ProxySelector.getDefault();
cookieJar = CookieJar.NO_COOKIES;
socketFactory = SocketFactory.getDefault();
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;
authenticator = Authenticator.NONE;
connectionPool = new ConnectionPool();
···
}
public OkHttpClient build() {
return new OkHttpClient(this);
}
如果我们要采用构建者来初始化OkHttp,我们需要先获取Builder的实例,调用Builder提供的方法,进行参数配置,最后调用Builder的build方法,将Builder传入OkHttpClient的无参构造,返回OkHttpClient
构建者模式可以通过链式调用构建对象,在构建复杂对象的时候可以减少代码量,并对其进行约束
在OkHttp3.0+版中很多地方都用到了这种设计模式(Builder),例如接下来的Request
构建Request对象
Request request = new Request.Builder()
.url("https://www.baidu.com/")
.get()
.build();
也是通过构建者模式获取,内部实现,这里我们就不看了
发送请求
Response response = okHttpClient.newCall(request).execute();
这里我们直接调用了OkHttpClient的newCall方法,传入了上面生产的Request对象
/**
* Prepares the {@code request} to be executed at some point in the future.
*/
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
内部实际上调用了RealCall的newRealCall静态方法
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.eventListener = client.eventListenerFactory().create(call);
return call;
}
生成了RealCall对象(RealCall是Call接口的实现类)
并对其注册了事件监听,这个监听将会在Call的各个周期中调用
执行
在newCall方法后,我们拿到了RealCall对象,如果我们希望这个请求是同步的,我们可以调用execute方法
我们来看看execute方法在RealCall类中的实现
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);
throw e;
} finally {
client.dispatcher().finished(this);
}
}
这里我们重点看
Response result = getResponseWithInterceptorChain();
getResponseWithInterceptorChain()直接返回了一个Response
我们都知道,OkHttp从3.0版本起,请求和响应都是用拦截器来实现
拦截器责任链
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
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, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
}
我们大概梳理一遍流程
首先把所有的拦截器都放入了一个List,
依次是:
用户设置的拦截器、
retryAndFollowUpInterceptor(重试重定向)、
BridgeInterceptor(将用户请求转化为真实的网络请求,网络响应转化为用户响应)、
CacheInterceptor(为 从缓存中请求、将响应写入缓存 服务)、
ConnectInterceptor(和目标服务器建立链接)、
networkInterceptors(如果不是WebSocket的话会添加,用户设置的网络拦截器)、
CallServerInterceptor(链中最后一个拦截器,向目标服务器发送请求)
用这些组成了RealInterCeptroChain,
最后调用了chain的proceed方法
这里我画了张图帮助大家理解
至此,我们就拿到了返回的Response,直接通过return返回
2,异步
要进行异步请求,需要传入回调,我们找到Call接口中除了execute还有一个enqueue方法,入参就是一个Callback
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
Request request = new Request.Builder()
.url("https://www.baidu.com/")
.get()
.build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: " + e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, "onResponse: " + response.body().string());
}
});
让我们来看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));
}
做了一些校验,然后用AsyncCall接收了回调(AsyncCall继承自NamedRunnable,NamedRunnable继承自Runnable)
这里我们主要看dispatcher的enqueue方法
client.dispatcher().enqueue(new AsyncCall(responseCallback));
synchronized void enqueue(AsyncCall call) {
//获取当前运行的异步请求的大小,如果小于最大请求的数量(默认64), 而且运行在当前主机的连接数小于每个主机最大的请求数(默认5)
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
如果满足if的条件,就会加入运行中的异步队列,并立刻加入线程池中去执行
如果不满足,就会放入准备执行的队列
既然是放入线程池中运行,最后肯定是调用Runnable的run方法,这里我们传入的是AsyncCall,它的run方法是在父类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();
}
这里很简单,只是调用了一下execute方法
@Override protected void execute() {
boolean signalledCallback = false;
try {
//与同步方法一致
Response response = getResponseWithInterceptorChain();
//如果OkHttp初始化时设置了重试,而且这个Call被取消了
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
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 {
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
}
getResponseWithInterceptorChain和同步方法中流程一样,这里不重复说了
如果交易成功返回,则会调用
responseCallback.onResponse(RealCall.this, response);
那么之前那些加入准备异步队列的请求什么时候调用呢?
在AsyncCall的execute方法的最后调用了dispatcher的finished方法
client.dispatcher().finished(this);
/** Used by {@code AsyncCall#run} to signal completion. */
void finished(AsyncCall call) {
finished(runningAsyncCalls, call, true);
}
private void finished(Deque calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
if (promoteCalls) promoteCalls();
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
因为传入的Call是AsyncCall,在调用finished方法时,promoteCalls传入的值为true
当有一个AsyncCall完成的时候,会推进下一个请求执行
重点看promoteCalls方法
private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return; // 大于上限,返回
if (readyAsyncCalls.isEmpty()) return; // 预备队列中已经空了,返回
for (Iterator i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
//如果每个主机运行的Calls小于上限
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
//执行
executorService().execute(call);
}
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
如果满足条件,会去遍历预备队列中的请求,依次加入线程池去执行,接下来的流程和上面一致了
3.总结
最后用一张图把同步和异步流程结合起来