Android OkHttp3簡介和使用詳解

一 OKHttp簡介

OKHttp是一個處理網絡請求的開源項目,Android 當前最火熱網絡框架,由移動支付Square公司貢獻,用於替代HttpUrlConnection和Apache HttpClient(android API23 6.0裏已移除HttpClient)。
OKHttpGitHub地址

OKHttp優點

  1. 支持HTTP2/SPDY(SPDY是Google開發的基於TCP的傳輸層協議,用以最小化網絡延遲,提升網絡速度,優化用戶的網絡使用體驗。)
  2. socket自動選擇最好路線,並支持自動重連,擁有自動維護的socket連接池,減少握手次數,減少了請求延遲,共享Socket,減少對服務器的請求次數。
  3. 基於Headers的緩存策略減少重複的網絡請求。
  4. 擁有Interceptors輕鬆處理請求與響應(自動處理GZip壓縮)。

OKHttp的功能

  1. PUT,DELETE,POST,GET等請求
  2. 文件的上傳下載
  3. 加載圖片(內部會圖片大小自動壓縮)
  4. 支持請求回調,直接返回對象、對象集合
  5. 支持session的保持

二 OkHttp3使用

主要介紹 OkHttp3 的 Get 請求、 Post 請求、 上傳下載文件 、 上傳下載圖片等功能 。

添加OkHttp3的依賴

compile 'com.squareup.okhttp3:okhttp:3.7.0'
compile 'com.squareup.okio:okio:1.12.0'

添加網絡權限

<uses-permission android:name="android.permission.INTERNET"/>

1.異步GET請求

        //1.創建OkHttpClient對象
        OkHttpClient okHttpClient = new OkHttpClient();
        //2.創建Request對象,設置一個url地址(百度地址),設置請求方式。
        Request request = new Request.Builder().url("http://www.baidu.com").method("GET",null).build();
        //3.創建一個call對象,參數就是Request請求對象
        Call call = okHttpClient.newCall(request);
        //4.請求加入調度,重寫回調方法
        call.enqueue(new Callback() {
            //請求失敗執行的方法
            @Override
            public void onFailure(Call call, IOException e) {
            }
            //請求成功執行的方法
            @Override
            public void onResponse(Call call, Response response) throws IOException {
            }
        });

上面就是發送一個異步GET請求的4個步驟:

  1. 創建OkHttpClient對象
  2. 通過Builder模式創建Request對象,參數必須有個url參數,可以通過Request.Builder設置更多的參數比如:header、method等
  3. 通過request的對象去構造得到一個Call對象,Call對象有execute()和cancel()等方法。
  4. 以異步的方式去執行請求,調用的是call.enqueue,將call加入調度隊列,任務執行完成會在Callback中得到結果。

注意事項:

  1. 異步調用的回調函數是在子線程,我們不能在子線程更新UI,需要藉助於 runOnUiThread() 方法或者 Handler 來處理。
  2. onResponse回調有一個參數是response,如果我們想獲得返回的是字符串,可以通過response.body().string()獲取;如果希望獲得返回的二進制字節數組,則調用response.body().bytes();如果你想拿到返回的inputStream,則調response.body().byteStream(),有inputStream我們就可以通過IO的方式寫文件(後面會有例子)。

2.同步GET請求

        //1.創建OkHttpClient對象
        OkHttpClient okHttpClient = new OkHttpClient();
        //2.創建Request對象,設置一個url地址(百度地址),設置請求方式。
        Request request = new Request.Builder().url("http://www.baidu.com").method("GET",null).build();
        //3.創建一個call對象,參數就是Request請求對象
        Call call = okHttpClient.newCall(request);
        //4.同步調用會阻塞主線程,這邊在子線程進行
        new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        //同步調用,返回Response,會拋出IO異常
                        Response response = call.execute();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();

同步GET請求和異步GET請求基本一樣,不同地方是同步請求調用Call的execute()方法,而異步請求調用call.enqueue()方法(具體2個方法的不同點我下一遍具體源碼詳解再說)。

3.POST請求提交鍵值對

        //1.創建OkHttpClient對象
        OkHttpClient  okHttpClient = new OkHttpClient();
        //2.通過new FormBody()調用build方法,創建一個RequestBody,可以用add添加鍵值對 
        RequestBody  requestBody = new FormBody.Builder().add("name","zhangqilu").add("age","25").build();
        //3.創建Request對象,設置URL地址,將RequestBody作爲post方法的參數傳入
        Request request = new Request.Builder().url("url").post(requestBody).build();
        //4.創建一個call對象,參數就是Request請求對象
        Call call = okHttpClient.newCall(request);
        //5.請求加入調度,重寫回調方法
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
            }
        });

上面就是一個異步POST請求提交鍵值對的5個步驟:

  1. 創建OkHttpClient對象。
  2. 通過new FormBody()調用build方法,創建一個RequestBody,可以用add添加鍵值對 ,FormBody 是 RequestBody 的子類。
  3. 創建Request對象,設置URL地址,將RequestBody作爲post方法的參數傳入。
  4. 創建一個call對象,參數就是Request請求對象。
  5. 請求加入調度,重寫回調方法。

通過對比我們發現異步的POST請求和GET請求步驟很相似。

4.異步POST請求提交字符串

POST請求提交字符串和POST請求提交鍵值對非常相似,不同地方主要是RequestBody,下面我們來具體看一下。
在有些情況下客戶端需要向服務端傳送字符串,我們該怎麼做?
我們需要用到另一種方式來構造一個 RequestBody 如下所示:

        MediaType mediaType = MediaType.parse("application/json; charset=utf-8");//"類型,字節碼"
        //字符串
        String value = "{username:admin;password:admin}"; 
        //1.創建OkHttpClient對象
        OkHttpClient  okHttpClient = new OkHttpClient();
        //2.通過RequestBody.create 創建requestBody對象
        RequestBody requestBody =RequestBody.create(mediaType, value);
        //3.創建Request對象,設置URL地址,將RequestBody作爲post方法的參數傳入
        Request request = new Request.Builder().url("url").post(requestBody).build();
        //4.創建一個call對象,參數就是Request請求對象
        Call call = okHttpClient.newCall(request);
        //5.請求加入調度,重寫回調方法
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
            }
        });

5.異步POST請求上傳文件

我們這裏舉一個上傳圖片的例子,也可以是其他文件如,TXT文檔等,不同地方主要是RequestBody,首先我們要添加存儲卡讀寫權限,在 AndroidManifest.xml 文件中添加如下代碼:

 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

下面我們具體看一下上傳文件代碼。

        //1.創建OkHttpClient對象
        OkHttpClient  okHttpClient = new OkHttpClient();
        //上傳的圖片
        File file = new File(Environment.getExternalStorageDirectory(), "zhuangqilu.png");
        //2.通過RequestBody.create 創建requestBody對象,application/octet-stream 表示文件是任意二進制數據流
        RequestBody requestBody =RequestBody.create(MediaType.parse("application/octet-stream"), file);
        //3.創建Request對象,設置URL地址,將RequestBody作爲post方法的參數傳入
        Request request = new Request.Builder().url("url").post(requestBody).build();
        //4.創建一個call對象,參數就是Request請求對象
        Call call = okHttpClient.newCall(request);
        //5.請求加入調度,重寫回調方法
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
            }
        });

6.異步GET請求下載文件

下載文件也是我們經常用到的功能,我們就舉個下載圖片的例子吧

        //1.創建OkHttpClient對象
        OkHttpClient okHttpClient = new OkHttpClient();
        //2.創建Request對象,設置一個url地址(百度地址),設置請求方式。
        Request request = new Request.Builder().url("https://www.baidu.com/img/bd_logo1.png").get().build();
        //3.創建一個call對象,參數就是Request請求對象
        Call call = okHttpClient.newCall(request);
        //4.請求加入調度,重寫回調方法
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.e(TAG, "onFailure: "+call.toString() );
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //拿到字節流
                InputStream is = response.body().byteStream();
                int len = 0;
                //設置下載圖片存儲路徑和名稱
                File file = new File(Environment.getExternalStorageDirectory(),"baidu.png");
                FileOutputStream fos = new FileOutputStream(file);
                byte[] buf = new byte[128];
                while((len = is.read(buf))!= -1){
                    fos.write(buf,0,len);
                    Log.e(TAG, "onResponse: "+len );
                }
                fos.flush();
                fos.close();
                is.close();
            }
        });

Get請求下載文件還是比較簡單,設置下載地址,在回調函數中拿到了圖片的字節流,然後保存爲了本地的一張圖片。

從網絡下載一張圖片並直接設置到ImageView中。

@Override
public void onResponse(Call call, Response response) throws IOException {
    InputStream is = response.body().byteStream();
    //使用 BitmapFactory 的 decodeStream 將圖片的輸入流直接轉換爲 Bitmap 
    final Bitmap bitmap = BitmapFactory.decodeStream(is);
    //在主線程中操作UI
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            //然後將Bitmap設置到 ImageView 中
            imageView.setImageBitmap(bitmap);
        }
    });

    is.close();
}

主要註釋已在代碼中了。

7.異步POST請求上傳Multipart文件

我們在有些情況下既要上傳文件還要上傳其他類型字段。比如在個人中心我們可以修改名字,年齡,修改圖像,這其實就是一個表單。這裏我們用到MuiltipartBody ,它 是RequestBody 的一個子類,我們提交表單就是利用這個類來構建一個 RequestBody,我們來看一下具體代碼。

        //1.創建OkHttpClient對象
        OkHttpClient  okHttpClient = new OkHttpClient();
        //上傳的圖片
        File file = new File(Environment.getExternalStorageDirectory(), "zhuangqilu.png");
        //2.通過new MultipartBody build() 創建requestBody對象,
         RequestBody  requestBody = new MultipartBody.Builder()
                //設置類型是表單
                .setType(MultipartBody.FORM)
                //添加數據
                .addFormDataPart("username","zhangqilu")
                .addFormDataPart("age","25")
                .addFormDataPart("image","zhangqilu.png",
RequestBody.create(MediaType.parse("image/png"),file))
                .build();
        //3.創建Request對象,設置URL地址,將RequestBody作爲post方法的參數傳入
        Request request = new Request.Builder().url("url").post(requestBody).build();
        //4.創建一個call對象,參數就是Request請求對象
        Call call = okHttpClient.newCall(request);
        //5.請求加入調度,重寫回調方法
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
            }
        });

注意事項

  1. 如果提交的是表單,一定要設置表單類型, setType(MultipartBody.FORM)
  2. 提交文件 addFormDataPart() 方法的第一個參數就是類似於鍵值對的鍵,是供服務端使用的,第二個參數是文件的本地的名字,第三個參數是 RequestBody,裏面包含了我們要上傳的文件的路徑以及 MidiaType。

三 結束

Android OkHttp3簡介和使用詳解就到這裏了,下一篇我們分析 OkHttp3源碼。

發佈了47 篇原創文章 · 獲贊 41 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章