摘要:okhttp是安卓端最火热的轻量级框架,由移动支付Square公司贡献,用于替换api23以后被移除的HttpClient

OkHttpClient

OkHttpClient 看名字就这到这代表的就是http的客户端一般都会在个静态块里初始化,那就先来分析下 初始化 OkHttpClient 这里,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
static {
//设置超时
builder = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.addInterceptor(new Interceptor() {
@Override public Response intercept(Interceptor.Chain chain) throws IOException {
Request originalRequest = chain.request();
//请求拦截器 在每次 发起请求的时候 在拦截器里 可以 增加 消息头
Request authorised = originalRequest.newBuilder()
.header(name, headerValue)
.build();
return chain.proceed(authorised);
}
});
mOkHttpClient=builder.build();
}

首先构造一个 builder

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
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();
dns = Dns.SYSTEM;
followSslRedirects = true;
followRedirects = true;
retryOnConnectionFailure = true;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
}

初始化一些值,重点新建了一个Dispatcher(分发器) 和一个 ConnectionPool(连接池) ,后面那些方法 其实就是设置初始化的这些
值,最后等到一个 builder对象 调用build();获得当前对象 这好像没啥可说的 哈哈哈哈哈

1
2
3
public OkHttpClient build() {
return new OkHttpClient(this);
}

Request

创建完OkHttpClient 客户端,接下来初始化请求对象 Request

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
requestBuilder=new Request.Builder().url(baseUrl+url);
formBodyBuilder = new FormBody.Builder();
formBodyBuilder.add(name,value);
public Builder() {
this.method = "GET";
this.headers = new Headers.Builder();
}
public static final class Builder {
private final List<String> names = new ArrayList<>();
private final List<String> values = new ArrayList<>();
public Builder add(String name, String value) {
names.add(HttpUrl.canonicalize(name, FORM_ENCODE_SET, false, false, true, true));
values.add(HttpUrl.canonicalize(value, FORM_ENCODE_SET, false, false, true, true));
return this;
}
public Builder addEncoded(String name, String value) {
names.add(HttpUrl.canonicalize(name, FORM_ENCODE_SET, true, false, true, true));
values.add(HttpUrl.canonicalize(value, FORM_ENCODE_SET, true, false, true, true));
return this;
}
public FormBody build() {
return new FormBody(names, values);
}

构建了 request 和formbody 这里其实可以设置参数

同步发送请求 mOkHttpClient.newCall(request).execute();

1
2
3
Request request = requestBuilder.post(formBodyBuilder.build()).build();
Response response = mOkHttpClient.newCall(request).execute();

Request 的build就不看了啊
直接看发送请求的方法
通过newCall 可以看到 这里new 了一个RealCall 然后调用了 在他的构造方法里创建了一个 RetryAndFollowUpInterceptor (重试连接
拦截器) 他的execute()方法,那看一下execute() 方法

Dispatcher

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override public Response execute() throws IOException {
synchronized (this) {
//这里又个判断 没有Call智能执行一次 如果第二次进来会报错
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}

可以看到 关键的又3句client.dispatcher().executed(this);getResponseWithInterceptorChain(); client.dispatcher().finished
(this);咱们一句一句看啊
dispatcher 咱们之前说了 是在OkHttpClient 初始化的时候创建的,看名字 他肯定是个分发器,分发什么,咱们分析的是个网络请求框
架,肯定分发请求没,点进去executed 方法看看。

1
2
3
4
/** Used by {@code Call#execute} to signal it is in-flight. */
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}

这是往一个同步的队列里放了一个回调对象 看看这队列是啥,这个类里面没那么多属性就一起看看吧.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public final class Dispatcher {
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
private Runnable idleCallback;
/** 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<>();

一看ExecutorService 就知道 这里肯定用到了线程池,在看看3个队列 两个异步一个同步的 ,现在猜测线程池可能是 异步请求用的
咱们先不看,现在怎们明确了 如果同步请求 我们是吧请求回调放到了一队列里处理。

再看getResponseWithInterceptorChain 方法,重点来了

getResponseWithInterceptorChain

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> 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 (!retryAndFollowUpInterceptor.isForWebSocket()) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(
retryAndFollowUpInterceptor.isForWebSocket()));
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}

先获取咱们之前自己配置的拦截器,如果没配置 咱们先忽略,然后又继续添加拦截器retryAndFollowUpInterceptor是在 RealCall 创建
的时候 创建的 然后 又创建了BridgeInterceptor 看参数 应该根cookie有关,然后是CacheInterceptor 一看就是缓存相关的,然后是
ConnectInterceptor 连接相关 networkInterceptors 先忽略,最后又放了个 CallServerInterceptor 拦截器,这么多拦截器组装成了
一个 list,接下来新建了一个 RealInterceptorChain(拦截器链)对象 ,并调用了 他的proceed 方法,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@Override public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpStream, connection);
}
public Response proceed(Request request, StreamAllocation streamAllocation, HttpStream httpStream,
Connection connection) 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.httpStream != null && !sameConnection(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.httpStream != null && calls > 1) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must call proceed() exactly once");
}
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpStream, connection, index + 1, request);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
// Confirm that the next interceptor made its required call to chain.proceed().
if (httpStream != 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");
}
return response;
}

看到 这个方法里面 又创建了一个 RealInterceptorChain ,然后调用了 拦截器的intercept 拦截器,返回了一个Response对象,
咱们随便点开一个框架里的拦截器,看一下 他的interceptor 方法,例如BridgeInterceptor 我们看到 这个方法里面调用了刚才 传入的
RealInterceptorChain 的proceed 方法,嗯?这不又回到了RealInterceptorChain 的proceed 方法。配合这个RealInterceptorChain 在
创建的时候 传入了一个index+1 我感觉,这里不简单,在看看其他的,都调用了proceed方法 ,在看看 我们自定义的拦截器,也是在
return了RealInterceptorChain 的proceed,原来是这样啊,这叫啥,递归吗。通过这种递归的方式,依次的先调用了我们自己的拦截器
,然后又调用了框架里写好的这几个拦截器。关于这些拦截器.单独开一个博客在说,继续往下看 getResponseWithInterceptorChain后调用了client.dispatcher().finished(this);而且是在finally 里面

client.dispatcher().finished(this);

这一看名字就知道 是请求完成的意思

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private <T> void finished(Deque<T> 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;

发送异步请求

发送异步请求根 同步前面差不多 差距是 调用了dispatcher().enqueue方法

1
2
3
4
5
6
7
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

client.dispatcher().enqueue(new AsyncCall(responseCallback));

1
2
3
4
5
6
7
8
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}

这里判断了一下 如果 默认当前最大的Requests的请求不超过64,并且访问当前host的请求不超过5个 (maxRequests 和maxRequestsPerHost 可以修改),就把call放到当前运行的队列,并且执行线程池,否者放到准备队列里去。

AsyncCall

AsyncCall 实现了 NamedRunnable 其实就是Runnable 只不过给当前线程起了名字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* Runnable implementation which always sets its thread name.
*/
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();
}

可以看到 在run函数里 调用了 execute

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Override protected void execute() {
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
//返回response
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);
}
} finally {
//移除队列里的 回调
client.dispatcher().finished(this);
}
}

呵呵 一点开 我就看到了 getResponseWithInterceptorChain,后面我也不打算看了 无非就是 调用回调方法 返回response,然后移除队列里的 Call.

整体流程我们就分析晚,如果没事,明天分下下 那几个拦截器,BridgeInterceptor,CacheInterceptor,ConnectInterceptor,CallServerInterceptor。