Okhttp原始碼分析&實踐(四)【Okhttp的整體框架和基本原始碼分析】
開啟掘金成長之旅!這是我參與「掘金日新計劃 · 12 月更文挑戰」的第26天
前面幾章,我們學習了http的基礎知識,服務端的基礎知識、服務端測試Demo的實踐編寫,本章開始,我們正式開始Okhttp的框架原始碼學習和實踐,大家要緊跟腳步哦,建議大家,可以跟隨小編,一點一點的敲一下文章中的程式碼,相信通過這個系列學習,您不單單會獲得okhttp的原始碼實踐知識,更多的可能,會總結得到
一份自我學習、實踐的方式方法
。
1.從使用入手,初探原始碼
我們先從okhttp的經典使用入手,試著瞭解、猜測一下okhttp的整體實現邏輯。
```java OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
Request request = new Request.Builder().url("http://www.baidu.com").cacheControl(CacheControl.FORCE_CACHE).build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@java.lang.Override
public void onFailure(Call call, IOException e) {
}
@java.lang.Override
public void onResponse(Call call, Response response) throws IOException {
response.toString();
}
});
```
1.1 OkHttpClient
首先我們關注到
java
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
我們看一下有哪些介面?
可以看到,這裡關鍵的就是攔截器新增介面、設定cookie、設定超時介面、執行器的設定介面。
從介面可以大概看出,okhttpclient很像外觀模式,okhttp對外界封裝的一個主要功能模組,通過建造者模式,可以對其裡面預設的執行器、執行步驟進行修改。
這裡有小夥伴問了,攔截器是個啥?我們來看一下介面定義
```java
package okhttp3;
public interface Interceptor { //進行攔截,請求處理 Response intercept(Chain chain) throws IOException; //chain是請求的封裝類 interface Chain { Request request(); //原始請求資料 //核心方法,處理請求,獲取response Response proceed(Request request) throws IOException;
@Nullable Connection connection();
Call call();
int connectTimeoutMillis();
Chain withConnectTimeout(int timeout, TimeUnit unit);
int readTimeoutMillis();
Chain withReadTimeout(int timeout, TimeUnit unit);
int writeTimeoutMillis();
Chain withWriteTimeout(int timeout, TimeUnit unit);
} }
``` 好了,先看到這裡,淺嘗輒止,我們後面從自我實現中,再窺探它的奧祕。
1.2 Request
```java Request request = new Request.Builder().url("http://www.baidu.com").cacheControl(CacheControl.FORCE_CACHE).build();
``` Request的使用也特別簡單,通過一個建造者模式,將使用者的請求,封裝為一個requset實體類,這裡就這麼簡單,真正使用Requset實體物件訊息的類是後面的具體請求執行者。
1.3 Request 到 Call的轉換
從使用上,上面一步只是新建了Requset物件,那麼Requset物件如何與請求相互關聯起來,就是接下來這句程式碼的作用了。
```java Call call = okHttpClient.newCall(request);
```
我們具體看一下,這裡幹什麼了?
OkHttpClient.java # newCall
java
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
一看,原來只是對requset進行了一層包裝,轉換為了RealCall物件。
RealCall .newRealCall
java
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物件,到底有哪些功能?還記得我們之前Android原始碼設計模式系列課程中,一直著重提到的思想嗎?面向介面程式設計,大家從表面看到現在,是否發現?OKhttp,不過是Call、Interceptor等面向使用者的,都是面向介面程式設計,這樣設計編碼,程式碼的可擴充套件性,更加強壯。
所以這裡關鍵開始轉換為,Call介面到底定義了哪些功能?
1.4 Call介面的定義
```java
public interface Call extends Cloneable { //獲取包裝的requset物件,這個很好理解 Request request(); //同步執行器,執行請求,將返回資料,直接返回 Response execute() throws IOException; //非同步執行器,通過callback非同步返回 void enqueue(Callback responseCallback);
/* 取消一個請求 / void cancel(); //是否以及執行 boolean isExecuted(); //是否已經取消 boolean isCanceled(); //克隆一個請求,大家還記得克隆涉及到的設計模式是什麼嗎? //忘記的小夥伴,需要再去詳細看一下小編的Android原始碼設計模式系列課程了 Call clone(); //工廠模式 interface Factory { Call newCall(Request request); } }
```
從介面函式定義來看,Call介面,即是最重要的功能類。這裡應該會將具體的使用者請求,進行網路請求處理,訪問服務端,然後進行資料處理,最終通過非同步或者同步,返回給客戶端。
1.5 發起請求,處理返回
接下來,繼續看,okhttp關鍵使用的最後一步程式碼
```java call.enqueue(new Callback() { @java.lang.Override public void onFailure(Call call, IOException e) {
}
@java.lang.Override
public void onResponse(Call call, Response response) throws IOException {
response.toString();
}
});
```
果然如我們上面分析一樣,這裡使用call發起了請求,並且對返回資料,可以通過非同步或者同步處理。
1.6 小結
好了,原始碼從使用入手,我們先簡單分析到這裡,有人會問,okhttp的關鍵原始碼,還沒講呢?的確,從上面關鍵四步的初步原始碼分析,我們只能瞭解okhttp的外在框架設計是怎麼樣的?並不能瞭解,okhttp內部是如何一一實現這些細節的?
但是,我想問大家一個問題,你們覺得是自己看一個知識總結收穫更多,還是說,您一點一滴的去實現一個框架,然後結合原始碼再去反思,這樣學到的更多呢?
有很多人會說,小編,並不是我不想去做,而是okhttp那麼複雜,我怎麼可能去自我實現一個呢?的確,說實話,我們去實現一個完全的okhttp,短時間肯定沒有可能,而且也根本沒有必要,但是,我們實現一個okhttp框架,使用自己已知的知識,去實現其主要的基本功能,這應該是可以的吧。
這裡小編明確,實現並不是關鍵,畢竟已有的框架、已有的知識總結一大堆,我們並非是要花費時間重複造輪子,但是藉助這個自我實踐過程,去進行自我的知識沉澱、累加,進而吃透okhttp,這才是最關鍵的
。
好了,大家準備好了嗎?我們要開始飆車了。