okhttp框架源碼分析從同步&異步請求使用開始

對於okhttp在現在項目中的普及程度已經不言而喻啦,基本上現在網絡請求都會基於它去進行封裝,而非前幾年用Android的網絡框架HttpURLConnection和Apache HttpClient去進行底層網絡訪問的封裝了,就目前而言它應該是最火熱的網絡請求開源項目了,既然這麼多公司的項目都採用它確定是有緣由的,因此百度百科上對它的優劣列舉了下:android

另外再閒扯一下,它是由移動支付Square公司貢獻的,說到Square,我想有一位Android大神不得不提,看圖說話:面試

其中它對okhttp的貢獻至關之大:網絡

好了,回到正題,對於這麼優秀的一個開源框架,若是隻是停留在如何使用它貌似確實有點浪費了,另外還有一個緣由就是現在android面試並不是前幾年了,對於技術的要求也愈來愈高了,而面試中只問你如何在項目中使用主流的三方開源框架我想是愈來愈少了,因此,接下來準備一點點去從源碼的角度去分析它的機制,固然因爲它的代碼量巨大,要想所有搞明白那也挺費盡的,重點是從其流程原理上進行有針對性的分析。app

在正式進行源碼分析以前先來看一下使用okhttp如何網絡請求,而它提供了兩種請求方式:同步和異步,下面開始。框架

同步請求:異步

 首先加入okhttp的官方依賴,這裏採用okhttp3.9.0這個版本進行學習,首先在gradle中加入依賴:ide

接着在界面中增長一個按鈕,點擊它則進行同步請求:源碼分析

而具體代碼的實現過程以下:學習

一、建立OkHttpClient對象:gradle

對於HttpClient咱們都很熟悉,這是以前Android庫中的網絡使用對象,回憶一下:

而在使用okhttp時,第一步其實也是相似,須要建立OkHttpClient,以下:

上面這句代碼就已經將OkHttpClient建立完了麼?試想一下對於網絡請求是否是得配置不少的一些參數,如網絡超時等,而對於參數的配置最適合最優雅的方式則是採用Builder模式,而OkHttpClient對於參數的構建就是這麼搞的,因此將其改成用Builder模式去構建以下:

其中設置了5秒的讀取超時時間,固然還能夠設置很是多的參數,點一下就能夠看到:

其怎麼使用Builder模式,這個以後在源碼分析中會詳細去閱讀的,不過這裏能夠簡單的瞅一眼大體構建過程,那就打開OkHttpClient的源代碼:

而針對每一個參數定義了一個對外調用的方法,方法的重點是返回Builder這個內部類對象自身,這樣就能夠不斷的以點的方式鏈式的進行參數的配置,以我們已經使用到的readTimeout()爲例:

當全部參數都設置完畢以後,最後調用它的build()方法進行OkHttpClient對象的構建,以下:

基於上已經分析清楚了使用Builder模式的步驟,在實際開發中若是遇到有不少參數要進行配置利用這個模式體驗上會比較好,能夠校仿一下。

二、建立Request對象:

對於這個對象的建立也是採用Builder方式進行構建,可見Builder模式仍是至關好用的,由於在這個對象中也是有一些參數須要進行配置,如URL、請求方式等,因此下面就不過多的解釋了,直接上代碼:

上面是採用get方式,對比一下我們傳統的代碼,其實也差很少,傳統代碼中用HttpGet來直觀的表達請求:

三、將Request封裝成Call對象:

對於Request和OkHttpClient如何關連起來呢?這裏就它這種關聯封裝成了Call對象了,以下:

四、調用Call的execute()發送同步請求:

最後我們運行看一下效果,固然在運行以前須要給app加入訪問網絡的權限,這裏就很少說了:

足以證實它確實是以同步的方式去請求網絡的,要想不報錯那固然得將這個請求放到子線程嘍,因而乎:

再次編譯運行:

異步請求:

先增長一個異步請求的button:

相比上面的同步請求,異步請求的實現步驟基本上差很少,以下:

一、建立OkHttpClient對象:

二、建立Request對象:

三、將Request封裝成Call對象:

四、調用Call的enqueue方法進行異步請求:

可是,其實OkhttpClient對於APP而言只要建立一次既可,並不用每次請求就得建立一下它,因此能夠將它提取出來,由每一個不一樣的請求共享它:

public class MainActivity extends AppCompatActivity {

    private static final OkHttpClient OK_HTTP_CLIENT = new OkHttpClient.Builder()
            .readTimeout(5, TimeUnit.SECONDS) .build();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    /**
     * 同步請求
     */
    public void synRequest(View view) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                //二、建立Request對象
                final Request request = new Request.Builder().url("http://www.baidu.com")
                        .get().build();
                //三、將Request封裝成Call對象
                Call call = OK_HTTP_CLIENT.newCall(request);
                //四、調用Call的execute()發送同步請求
                try {
                    Response response = call.execute();
                    Log.e("cexo", response.body().string());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    /**
     * 異步請求
     */
    public void asycRequest(View view) {
        //二、建立Request對象
        final Request request = new Request.Builder().url("http://www.baidu.com")
                .get().build();
        //三、將Request封裝成Call對象
        Call call = OK_HTTP_CLIENT.newCall(request);
        //四、調用Call的enqueue方法進行異步請求
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.e("cexo", "request failed:" + e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                Log.e("cexo", "request successed:" + response.body().string());
            }
        });
    }
}

編譯運行:

可見確實是在子線程執行的,也說明是異步請求。

【注意】:異步請求回調onResponse()和onFailure()方法都是在子線程執行的,這個是比較容易忽視的,下面來實驗下:

編譯運行:

總結:

對於OkHttp的同步和異步請求須要記住的是:

一、發起請求的方法調用:同步請求是調用Call.execute();異步請求是調用Call.enqueue()。

二、阻塞線程與否:同步阻塞、異步不阻塞。

相關文章
相關標籤/搜索