Okhttp 基礎(chǔ)知識導(dǎo)圖

Okhttp 使用
1,創(chuàng)建一個客戶端。
2,創(chuàng)建一個請求。
3,發(fā)起請求(入?yún)⒒卣{(diào))。
Request request = new Request.Builder().url( "http://xxxxx").build();
//創(chuàng)建客戶端
OkHttpClient mOkHttpClient= new OkHttpClient.Builder()
.connectTimeout(30000, TimeUnit.MICROSECONDS)
.readTimeout(30000, TimeUnit.MICROSECONDS)
.writeTimeout(30000, TimeUnit.MICROSECONDS).build();
//創(chuàng)建請求
Call mCall= mOkHttpClient.newCall(request);
//請求+回調(diào)
mCall.enqueue(new Callback() {
@Override
public void onFailure(Call arg0, IOException arg1) {
}
@Override
public void onResponse(Call arg0, Response arg1) throws IOException {
}
});
一、任務(wù)分發(fā)
網(wǎng)絡(luò)請求不能占用主線程資源,在多個請求并發(fā)條件下,需要一個管理器實現(xiàn)任務(wù)分發(fā),將任務(wù)交給線程池。

1,RealCall 類
Request 類是一個請求實體,配置 url,組裝 Header,請求體RequestBody, method 支持 GET、HEAD、POST、DELETE、PUT、PATCH。
每個 Request 實體創(chuàng)建一個 RealCall 對象,負責一個具體請求的 http 事務(wù)。
@Override
public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
Call 接口,內(nèi)部工廠 Call.Factory 的 newCall() 方法創(chuàng)建,OkHttpClient 類實現(xiàn)工廠接口,創(chuàng)建 RealCall。
RealCall 類同步方法。
@Override
public Response execute() throws IOException {
synchronized (this) {
...
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();//同步,耗時處
return result;
} finally {
client.dispatcher().finished(this);
}
}
異步方法。
@Override
public void enqueue(Callback responseCallback) {
synchronized (this) {
...
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
execute() 方法,同步請求需要自己實現(xiàn)線程池。enqueue() 方法,創(chuàng)建一個異步任務(wù),交給分發(fā)者,Dispatcher 類分發(fā),(同步或異步)。
2,Dispatcher 分發(fā)者
Dispatcher 類控制多個 http 請求的節(jié)奏,負責 RealCall 的并發(fā),管理(等待/運行)隊列,線程池調(diào)度。

synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
同步分發(fā),將 RealCall 對象加入同步隊列,表示 RealCall 正在執(zhí)行。
synchronized void enqueue(AsyncCall call) {
//maxRequests=64,maxRequestsPerHost=5
if (runningAsyncCalls.size() < maxRequests &&
runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);//加入運行隊列
executorService().execute(call);//線程池執(zhí)行任務(wù)
} else {
readyAsyncCalls.add(call);
}
}
異步分發(fā),maxRequests:最大請求數(shù)量,maxRequestsPerHost:每個主機最大并發(fā)請求數(shù)量。
滿足運行時,將 AsyncCall (Runnable 任務(wù),RealCall 內(nèi)部類),加入運行隊列,派發(fā)線程池處理,不滿足運行時,加入等待隊列。
3,請求結(jié)束
每次(同步/異步)請求完成時,在 try/finally() 方法結(jié)束,Dispatcher 類的 finished()方法。
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
//同步隊列刪除RealCall,異步運行隊列刪除AsyncCall任務(wù)
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
if (promoteCalls) promoteCalls();//異步promoteCalls參數(shù)是true
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
異步請求時,繼續(xù)查詢等待隊列中的請求。
private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return;
if (readyAsyncCalls.isEmpty()) return;
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();//滿足條件,等待隊列刪除
runningAsyncCalls.add(call);//加入運行中隊列
executorService().execute(call);//開始執(zhí)行
}
if (runningAsyncCalls.size() >= maxRequests) return;
}
}
遍歷等待隊列的任務(wù),滿足運行條件時,從等待隊列刪除,加入運行隊列,派發(fā)線程池。
二、線程池管理
分發(fā)者內(nèi)部閥值[0, Integer.MAX_VALUE]的緩存線程池。
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60,
TimeUnit.SECONDS,new SynchronousQueue<Runnable>(),
Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
- 不保留 corePoolSize 核心線程,最大可創(chuàng)建線程 MAX_VALUE。
- 工作線程 keepAliveTime 設(shè)置60存活期線程復(fù)用。
- SynchronousQueue 阻塞隊列不存儲元素,管道。
大量http請求并發(fā)時,線程池啟動多個工作線程(臨時線程),確保每個任務(wù)都有線程及時處理。
線程執(zhí)行主體是 NamedRunnable 類 run() 方法,子類是運行隊列中的 AsyncCall任務(wù)類,實現(xiàn) execute() 抽象方法。
AsyncCall 構(gòu)造方法,傳入外部Callback回調(diào)對象。
@Override
protected void execute() {
boolean signalledCallback = false;
try {
//觸發(fā)RealCall類的方法,AsyncCall任務(wù)類定義在RealCall類內(nèi)部。
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
} finally {
//異步請求結(jié)束后finish。
client.dispatcher().finished(this);
}
}
外部 RealCall 類的 getResponseWithInterceptorChain() 方法,(同步/異步)請求耗時操作,返回 Response 實體。
Response getResponseWithInterceptorChain() throws IOException {
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 (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
創(chuàng)建了一系列攔截器,鏈式處理,緩存、連接都通過攔截器鏈的節(jié)點實現(xiàn)。、
三、攔截器
攔截器順序
客戶端自定義攔截器
retryAndFollowUpInterceptor 攔截器
BridgeInterceptor 橋接
CacheInterceptor 緩存
ConnectInterceptor 連接
networkInterceptors 網(wǎng)絡(luò)
CallServerInterceptor 數(shù)據(jù)流讀寫
RealInterceptorChain 類是在攔截器之間傳遞的節(jié)點,第一次創(chuàng)建時,index 初始是0,入?yún)鬟f originalRequest 原始請求與攔截器列表。
在 RealInterceptorChain 類的 proceed() 方法,開始鏈式處理,利用攔截器表中各層攔截處理 Request 請求和 Response 回復(fù)。
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
..
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
//拋出異常
}
if (response == null) {
//拋出異常
}
return response;
}
查找攔截器鏈表 index 索引的 Interceptor,新建 index++ 的 RealInterceptorChain 節(jié)點,觸發(fā) Interceptor的intercept() 方法,傳遞新 Chain。
列表中每一個 Interceptor 攔截器的 intercept() 方法。
- 處理 Request 請求
- Chain 節(jié)點的 proceed() 方法
- 處理 Response 答復(fù)
每一個 Chain 節(jié)點 proceed() 方法邏輯。
- 查找下一個攔截器
- 創(chuàng)建新 Chain 節(jié)點
- 攔截器 intercept() 方法,傳入新節(jié)點
當 index++索引到達最后一個攔截器 CallServerInterceptor 時,真正向 Server 發(fā)送數(shù)據(jù),獲取 Response,然后遞歸一層層按原路返回。
攔截器列表前部分 Interceptor 優(yōu)先處理原始 Request,后部分優(yōu)先處理原始 Response。

public interface Interceptor {
Response intercept(Chain chain) throws IOException;
interface Chain {
Request request();
Response proceed(Request request) throws IOException;
Connection connection();
}
}
攔截器設(shè)計是一個遞歸調(diào)用過程,Chain 對象是鏈節(jié)點,proceed() 方法處理時,創(chuàng)建 index++的 Chain 新節(jié)點,傳遞給下一個攔截器。
proceed() 方法流入 Request 請求,流出 Response 答復(fù),攔截器目的是層層截斷流入與流出,先截流,加工處理,再放流。
四、緩存設(shè)計
五、連接池
六、數(shù)據(jù)流
任重而道遠