OKHttp同步網絡請求原理分析(圖文並茂,看困包賠)

Hello,All,我是來自58同城的一名Android開發工程師,在58集團從事APP的開發工作。在日常的工作和學習過程中我經常會碰到一些好玩的和有意思的Android小知識點,有些知識可能都從未注意到過。通過一個多月的收集和整理,我發現通過不斷地記錄這些問題達到了非常好的複習效果,從而幫助了工作上的持續進步,今天我也是把平時收集到的這些東西發出來供大家一起學習,共同成長,如果感覺好,歡迎點擊右側的留言、點贊、加關注,您的支持是我最大的動力。

PS:關注,私信我,幫你內推58,常年招聘前端,移動端,後端,算法。

也歡迎關注我的公衆號,在這裏可以找到我,同時,這裏會不定期地推送一些時下最熱門的技術文章和互聯網行業工作心路歷程

                                                                            


OKHTTP是現在最流行的Android輕量級網絡請求框架,他以其簡潔的請求流程和使用方式,成功地幹掉了Volley等老牌網紅框架,並且吸引着越來越多的app開發者加入用戶陣營。

同樣,在58中臺的Passport SDK中也應用到了OKHTTP技術來處理登錄,賬號找回等前後端交互流程。

爲了能夠更加自如地運用他,今天我們就來詳細的瞭解一下OKHTTP到底是怎麼幫我們完成複雜的網絡請求過程。並且,通過學習他的處理流程,是否可以自己搭建一個類似的處理框架來提供給別人使用。

先從最經典的網絡請求開始

OkHttpClient okHttpClient = new OkHttpClient();

 先new了一個okHTTPClient對象出來,我們來看看okHttpClient裏面都做了些什麼

 通過默認的構造方法,我們看到最終是調用到了OkhttpClient.Builder並且new了一個Builder出來傳入到了OkHttpClient

其實很多時候我們從一個類的構造函數當中就可以看出來這個類的大致作用,尤其是這種Builder建造者設計模式,我們可以看到,在OKHTTPClient的Builder中可以配置很多client端的處理需求,如:是否重試,超時時間,配置dns,配置HTTP協議版本等操作,這些參數都會在請求的處理當中被使用到。

好,我們接着往下看:

        Request.Builder okRequestBuilder = new Request.Builder().url(builder.build());

 這裏是進行了request的一個配置過程,通過查看Request的源碼我們可以發現,這裏同樣是完成了一個請求參數的配置過程:

通過Android Studio的Structure功能我們可以很清楚地看到Request類的結構,其中,我們可以通過他的Builder來配置body,header,tag,url等請求參數

接下來

            Response response = client.newCall(okRequestBuilder.build()).execute();

我們可以看到,這一條語句纔是真正地發出了網絡請求,其中,newCall調用之後其實是返回了一個RealCall對象,然後調用了他的execute()方法來完成同步請求,好,我們來看源碼:

可以看到,在標註爲1的地方調用了一個eventListener對象的callStart方法,這個方法是做什麼用的呢?讓我們進入到他的實現類來看看

可以看到,EventListener其實是一個抽象類,但其中預留了很多的回調函數,包括callStart,dnsStart等等功能性函數。看到這是不是有種似曾相識的感覺?

沒錯,我們在配置Request的時候也配置過這些參數進來,這樣,在網絡請求的各個階段,OKHTTP就會通知我們網絡請求的各個狀態。當然,這裏的create使用的是建造者設計模式,他的實現必須是由我們用戶自己來定義的。

在源碼中標記爲2的地方我們能夠看到,Request最終是通過調用調度器Dispatcher的executed來把當前的對象進行了一個傳入,注意,這裏是executed方法,爲什麼不是execute呢?好,我們來看看他的實現

通過實現我們可以看到,最終是將這個請求加入到了一個ArrayDeque雙端隊列中。ArrayDeque是什麼鬼?爲什麼不是LinkedList?我們先留點神祕,後面再來進行詳細的探討。

緊接着,就進入到了攔截器的處理階段

這裏可以看到,okhttp先是構建了一個數組容器,然後先將用戶自定義添加的各種攔截器進行入隊操作,注意,這裏的攔截器其實是有先後順序的。

初始化完攔截器容器就進入到了責任鏈處理階段,這裏我們能夠看到,這個操作是委託給了一個叫RealInterceptorChain的Interceptor實現類來進行的(RealInterceptorChain是Interceptor.Chain的唯一實現),並最終調用了他的proceed方法。讓我們來看看proceed方法裏到底做了些什麼。

 public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
    if (index >= interceptors.size()) throw new AssertionError();

    calls++;

。。。
    // Call the next interceptor in the chain.
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);

    。。。

    return response;
  }

可以看到,進入到這個方法之後首先是進行了一個計數自增的操作,這個自增的標誌其實是用來控制攔截器容器裏各種攔截器的訪問次序的。然後,OKHttp通過創建一個RealInterceptorChain的next對象並且獲取到了容器中的相應index位置的攔截器,最後,通過調用interceptor的intercept方法來實現了攔截器內定義方法的執行,爲了整體篇幅的考慮,我們在後續的文章中再來對這幾個攔截器進行詳細的解析。

好,經過攔截器的處理之後,最終是得到了response對象,也就是我們的result。

到了這裏,OKHTTP的同步網絡請求過程就分析完了,可以看到,其中最核心的就要數對相關設計模式的應用了,我們來總結一下:

OkHttpClient及Request的配置過程:Builder建造者設計模式

EventListener的構建過程:Factory工廠模式

RealInterceptorChain的處理過程:責任鏈設計模式

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章