一、okhttp背景…
二、使用步驟
1、創建OkHttpClient;
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
這一個過程到底做了什麼?
最張調用 OkHttpClient(Builder builder)得到實例並賦值。
賦值了哪些參數?
private 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.proxySelector = builder.proxySelector;
this.cookieJar = builder.cookieJar;
this.cache = builder.cache;
this.internalCache = builder.internalCache;
this.socketFactory = builder.socketFactory;
boolean isTLS = false;
for (ConnectionSpec spec : connectionSpecs) {
isTLS = isTLS || spec.isTls();
}
if (builder.sslSocketFactory != null || !isTLS) {
this.sslSocketFactory = builder.sslSocketFactory;
this.certificateChainCleaner = builder.certificateChainCleaner;
} else {
X509TrustManager trustManager = systemDefaultTrustManager();
this.sslSocketFactory = systemDefaultSslSocketFactory(trustManager);
this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
}
this.hostnameVerifier = builder.hostnameVerifier;
this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
certificateChainCleaner);
this.proxyAuthenticator = builder.proxyAuthenticator;
this.authenticator = builder.authenticator;
this.connectionPool = builder.connectionPool;
this.dns = builder.dns;
this.followSslRedirects = builder.followSslRedirects;
this.followRedirects = builder.followRedirects;
this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
this.connectTimeout = builder.connectTimeout;
this.readTimeout = builder.readTimeout;
this.writeTimeout = builder.writeTimeout;
}
參數解釋:
1)dispatcher:請求的執行器,負責請求的同步執行、異步執行、取消、以及最多可以同時執行的請求數。
包含三個請求隊列:
readyAsyncCalls,準備執行的異步請求列隊,(當同時請求數大於maxRequests時,會將請求存入到這列隊)
runningAsyncCalls:正在執行的異步請求列隊(未取消和未結束)
runningSyncCalls:正在執行的同步請求列隊(未取消和未結束)
2)proxy:網絡的代理設置,可以通過他給網絡請求設置代理
3)protocols:支持的Protocol協議,Protocol和Url類似,java.net.URI.getScheme()返回url的協議(http, https, etc),而Protocol.get()返回的協議更加具體(http/1.0,http/1.1,h2,etc)
4)connectionSpecs : 支持套接字連接協議.
5)interceptors: 攔截器。可觀察每個調用的全部跨度
6)networkInterceptors : 攔截器。可觀察一個網絡請求和響應
7)proxySelector :代理服務器選擇器
8)cookieJar :提供cookie可持久化操作。
9)cache:緩存
10)internalCache:okhttp的內部緩存,使用者不應該使用它,用cache即可。
11)socketFactory :創建套接字的工廠類
12)sslSocketFactory:創建ssl套接字工廠類
13)certificateChainCleaner:證書
14)hostnameVerifier:主機名驗證
15)certificatePinner:約束所信任的證書
16)proxyAuthenticator:身份驗證代理服務器
17)authenticator:身份驗證代理服務器
18)connectionPool:連接池用於回收利用HTTP和HTTPS連接。
19)dns:dns服務器;默認使用系統的
20)followSslRedirects:是否支持sslhttp重定向,默認true
21)followRedirects:是否支持http重定向,默認true
22)retryOnConnectionFailure:連接失敗時是否重試,默認true
23)connectTimeout:連接超時
24)readTimeout:讀取超時
25)writeTimeout:寫入超時
參數有些多,大致瞭解可以幫我們更容易理清okhttp整體流程
2、創建Request;
private Request(Builder builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = builder.headers.build();
this.body = builder.body;
this.tag = builder.tag != null ? builder.tag : this;
}
參數說明,這個看着清爽:
1)url:請求地址
2)method :請求方法
3)headers :請求頭
4)body:請求體
5)tag:請求標記
3、創建Call,
Call = okHttpClient.newCall(Request);
實際上調用了
protected RealCall(OkHttpClient client, Request originalRequest) {
this.client = client;
this.originalRequest = originalRequest;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client);
}
這裏添加 retryAndFollowUpInterceptor 攔截器,通過這個攔截實現了重新請求及取消請求功能
4、重頭戲來了。(這裏先看看異步請求),enqueue(Callback responseCallback);
1)開始執行請求:
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
如果已經被執行就拋異常,所以一個call就能調一次execute、enqueue。
2) client.dispatcher().enqueue(new AsyncCall(responseCallback));
調用該請求的client的執行器來執行該請求。
這裏先創建了一個Runable的子類AsyncCall。
3)dispatcher 類中
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
看看請求列表有沒有滿。沒有滿,加入到正在執行列表,然後直接執行。否則放到等待隊列。
4)AsyncCall類中,直接在代碼中註解了
@Override protected void execute() {
//標記有沒有執行回調
boolean signalledCallback = false;
try {
//核心、獲取到response,看下面註釋
Response response = getResponseWithInterceptorChain();
//如果取消的就直接回調onFailure,傳入new IOException("Canceled")異常。
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 {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
//最後,結束這個call,看下面
client.dispatcher().finished(this);
}
}
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();//promoteCalls()是爲了在滿足要下(正在執行的異步任務數小於maxRequests)把準備請求列裏的請求轉至正在請求隊列,並執行它。
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();//如果分發器沒有需要執行的工作,處理idle狀態,會執行該回調
}
}
RealCall類裏面
private Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
//下面是添加一系列攔截器,個人覺得這裏是體現okhttp精華所在的勝地,看到這裏,都會激動的不要不要的!
interceptors.addAll(client.interceptors());
//網絡重試及取消的處理
interceptors.add(retryAndFollowUpInterceptor);
//cookie處理
interceptors.add(new BridgeInterceptor(client.cookieJar()));
//okhttp的內部緩存處理
interceptors.add(new CacheInterceptor(client.internalCache()));
//打開目標服務器的連接
interceptors.add(new ConnectInterceptor(client));
//如果不是forWebSocket,添加網絡重試及取消攔截器
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);
}
RealInterceptorChain類中 貼出核心代碼
public Response proceed(Request request, StreamAllocation streamAllocation, HttpStream httpStream,
Connection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
Call the next interceptor in the chain.
獲取到下個攔截(攔截是從0開關順序執行的,結後執行是的CallServerInterceptor攔截器,所以在CallServerInterceptor攔截器中就看不到Chain.proceed(Request request)了)
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpStream, connection, index + 1, request);
Interceptor interceptor = interceptors.get(index);
//讓下個攔截去處理所要處理的邏輯
Response response = interceptor.intercept(next);
return response;
}
三、總結
看完後
美妙無窮