剛開始接觸android,使用的網絡框架是Android-async-http,以後是volley,從2016年開始,項目所有開始使用okHttp。目前來講,OkHttp是Android端最火熱的輕量級框架,由移動支付Square公司貢獻用於替代HttpUrlConnection和Apache HttpClient。android
最新版本版本git
implementation 'com.squareup.okhttp3:okhttp:3.10.0'複製代碼
項目地址:https://github.com/square/okhttp,stars:2.5w+github
okhttp的之因此如此受歡迎,特色以下:緩存
先從使用上來入手,okHttp能夠構造異步和同步的網絡請求,分別以下:bash
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain(false);
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}複製代碼
首先加鎖置標誌位,接着使用分配器dispatcher的executed方法將call加入到同步隊列中,而後調用getResponseWithInterceptorChain方法(稍後分析)執行http請求,最後調用finishied方法將call從同步隊列中刪除。
服務器
void enqueue(Callback responseCallback, boolean forWebSocket) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));
}複製代碼
一樣先置標誌位,而後將封裝的一個執行體放到異步執行隊列中。這裏面引入了一個新的類AsyncCall,這個類繼承於NamedRunnable,實現了Runnable接口。NamedRunnable能夠給當前的線程設置名字,而且用模板方法將線程的執行體放到了execute方法中,而後根據隊列時序執行。
網絡
除了同步調用和異步調用,OkHttp還提供了一個攔截器的概念。攔截器提供了攔截請求和攔截服務器應答的接口。OkHttp提供了一個攔截器鏈的概念,經過將一個個攔截器組合成一個攔截器鏈,能夠達到在不一樣層面作不一樣攔截操做的效果,有點AOP的意思。攔截器後面有詳細分析。架構
上圖是OkHttp的整體架構,大體能夠分爲如下幾層:併發
接口層接收用戶的網絡訪問請求(同步請求/異步請求),發起實際的網絡訪問。OkHttpClient
是OkHttp框架的客戶端,更確切的說是一個用戶面板。用戶使用OkHttp進行各類設置,發起各類網絡請求都是經過OkHttpClient
完成的。每一個OkHttpClient
內部都維護了屬於本身的任務隊列,鏈接池,Cache,攔截器等,因此在使用OkHttp做爲網絡框架時應該全局共享一個OkHttpClient
實例。框架
Call
描述一個實際的訪問請求,用戶的每個網絡請求都是一個Call
實例。Call
自己只是一個接口,定義了Call
的接口方法,實際執行過程當中,OkHttp會爲每個請求建立一個RealCall
,每個RealCall
內部有一個AsyncCall
:
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
String host() {
return originalRequest.url().host();
}
Request request() {
return originalRequest;
}
RealCall get() {
return RealCall.this;
}
@Override protected void execute() {
...
}
...
}複製代碼
AsyncCall
繼承的NamedRunnable
繼承自Runnable接口
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();
}複製代碼
因此每個Call就是一個線程,而執行Call的過程就是執行其execute
方法的過程。
Dispatcher
是OkHttp的任務隊列,其內部維護了一個線程池,當有接收到一個Call
時,Dispatcher
負責在線程池中找到空閒的線程並執行其execute
方法。這部分將會單獨拿一篇博客進行介紹,詳細內容可參考本系列接下來的文章。
Protocol層負責處理協議邏輯,OkHttp支持Http1/Http2/WebSocket協議,並在3.7版本中放棄了對Spdy協議,鼓勵開發者使用Http/2。
鏈接層顧名思義就是負責網絡鏈接。在鏈接層中有一個鏈接池,統一管理全部的Socket鏈接,當用戶新發起一個網絡請求時,OkHttp會首先從鏈接池中查找是否有符合要求的鏈接,若是有則直接經過該鏈接發送網絡請求;不然新建立一個網絡鏈接。
RealConnection
描述一個物理Socket鏈接,鏈接池中維護多個RealConnection實例。因爲Http/2支持多路複用,一個RealConnection
能夠支持多個網絡訪問請求,因此OkHttp又引入了StreamAllocation
來描述一個實際的網絡請求開銷(從邏輯上一個Stream
對應一個Call
,但在實際網絡請求過程當中一個Call
經常涉及到屢次請求。如重定向,Authenticate等場景。因此準確地說,一個Stream
對應一次請求,而一個Call
對應一組有邏輯關聯的Stream
),一個RealConnection
對應一個或多個StreamAllocation
,因此StreamAllocation
能夠看作是RealConenction
的計數器,當RealConnection
的引用計數變爲0,且長時間沒有被其餘請求從新佔用就將被釋放。
鏈接層是OkHttp的核心部分,這部分固然也會單獨拿一篇博客詳細講解,詳細內容可參考本專題相關文章。
Cache層負責維護請求緩存,當用戶的網絡請求在本地已有符合要求的緩存時,OkHttp會直接從緩存中返回結果,從而節省網絡開銷。這部份內容也會單獨拿一篇博客進行介紹,詳細內容可參考本專題相關文章。
I/O層負責實際的數據讀寫。OkHttp的另外一大有點就是其高效的I/O操做,這歸因於其高效的I/O庫okio
這部份內容筆者也打算另開一個專題進行介紹。詳細內容能夠參考本博客相關內容。
攔截器層提供了一個類AOP接口,方便用戶能夠切入到各個層面對網絡訪問進行攔截並執行相關邏輯。在下一篇博客中,筆者將經過介紹一個實際的網絡訪問請求實例來介紹攔截器的原理。