OkHttp3.x解析(一) OkHttp介紹以及基本使用

OkHttp是一個目前流行高效的HTTP客戶端:

  • HTTP/2支持允許對同一主機的所有請求共享一個套接字。
  • 連接池減少了請求延遲(如果HTTP/2不可用)。
  • 透明的GZIP壓縮了下載文件的大小。
  • 響應緩存完全避免了網絡中的重複請求。

當網絡出現問題的時候OkHttp依然堅守自己的職責,當網絡出現問題的時候OkHttp依然堅守自己的職責,它會自動恢復一般的連接問題,如果你的服務有多個IP地址,當第一個IP請求失敗時,OkHttp會交替嘗試你配置的其他IP,OkHttp使用現代TLS技術(SNI, ALPN)初始化新的連接,當握手失敗時會回退到TLS 1.0。

OkHttp目前支持 Android 5.0 及以上版本Android平臺, 對於 Java, JDK 1.7及以上.

但是不排除有部分低版本忠實粉絲,升級困難綜合徵晚期患者,因此:

The OkHttp 3.12.x branch supports Android 2.3+ (API level 9+) and Java 7+. These
 platforms lack support for TLS 1.2 and should not be used. But because upgrading 
 is difficult we will backport critical fixes to the 3.12.x branch through 
 December 31, 2021.
相關依賴庫導入:
implementation 'com.squareup.okhttp3:okhttp:4.2.2'
另外還需要導入一個內部依賴庫:
implementation 'com.squareup.okio:okio:2.2.2'
相關庫GitHub地址

OkHttp

OkIo
Okio這個庫的功能從字面意思上理解就是處理IO操作的(OkHttp字面意思不也是處理http操作的麼),具體原理細節後面單開章節再表。

友情提示記得添加網絡權限
<uses-permission android:name="android.permission.INTERNET"/>

下面開始介紹常用的幾個請求的使用方法。
創建一個代理類:

public class OkHttpProxy {
    private static OkHttpProxy instance = null;
//   創建OkHttpClient對象
    private OkHttpClient client;
    private OkHttpProxy() {
          client = new OkHttpClient.Builder()
          .callTimeout(6000, TimeUnit.MILLISECONDS)
          .connectTimeout(6000, TimeUnit.MILLISECONDS)
          .readTimeout(20000, TimeUnit.MILLISECONDS)
          .writeTimeout(20000, TimeUnit.MILLISECONDS)
          .build();
    }
    public static OkHttpProxy getInstance() {
        synchronized (OkHttpProxy.class) {
            if (instance == null) {
                instance = new OkHttpProxy();
            }
        }
        return instance;
    }
}

1.同步Get請求

首先創建get方式的 Request對象:

    /**
     * 獲取 get方式 Request 對象
     *
     * @param reqName 接口名稱
     * @param param   參數
     * @return Request 對象
     */
    private Request getRequest(String reqName, Map<String, String> param) {
//        創建Request對象,設置一個url地址,設置請求方式。
        Request.Builder reqBuild = new Request.Builder();
        HttpUrl.Builder urlBuilder = HttpUrl.parse(BASE_URL + reqName)
                .newBuilder();
        for (Map.Entry<String, String> entry : param.entrySet()) {
            urlBuilder.addQueryParameter(entry.getKey(), entry.getValue());
        }
        return reqBuild.url(urlBuilder.build()).get().build();
    }

然後創建一個call對象,並使用同步方法發起請求:

    /**
     * 同步請求
     *
     * @param method       請求方式  get or post
     * @param reqName      接口名稱
     * @param param        參數
     * @param callResponse 請求回調
     */
    public void execute(String method, String reqName, Map<String, String> param, final CallResponse callResponse) {
        final Call call = client.newCall("get".equals(method)?getRequest(reqName, param):postRequest(reqName,param));
        //同步調用會阻塞主線程,這邊在子線程進行,這裏就直接使用線程了,如果項目中使用最好是用線程池
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Response response = call.execute();
                    callResponse(response, callResponse);
                } catch (Exception e) {
                    e.printStackTrace();
                    if (callResponse != null) {
                        callResponse.error(e);
                    }
                }
            }
        }).start();
    }
    /**
     * 處理請求結果
     *
     * @param response     請求結果
     * @param callResponse 回調接口對象
     * @throws IOException
     */
    private void callResponse(Response response, CallResponse callResponse) throws IOException {
        String body = response.body().string();
        if (!TextUtils.isEmpty(body)) {
            ResponseData responseData = JSONObject.parseObject(body, ResponseData.class);
            if ("success".equals(responseData.getType())) {
                callResponse.success(responseData.getList());
            } else {
                callResponse.fail(responseData.getMsg());
            }
        } else {
            callResponse.fail("請求失敗");
        }
    }

最後調用接口:

        ApiWork.getInstance().getinfolist("1", "10", new CallResponse() {
            @Override
            public void success(final String data) {
            		//這裏必須在主線程中更新UI,可以可以使用Handler
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            tvTitle.setText(data);
                        }
                    });
            }

            @Override
            public void fail(String msg) {
                Log.v("userlogin",msg);
            }

            @Override
            public void error(Exception e) {

            }
        });
2.異步Get請求

異步get請求只是在發起請求那與同步有區別,之前的步驟都一致:

/**
     * 異步請求
     *
     * @param method       請求方式  get or post
     * @param reqName      接口名稱
     * @param param        參數
     * @param callResponse 請求回調
     */
    public void enqueue(String method, String reqName, Map<String, String> param, final CallResponse callResponse) {
        final Call call = client.newCall("get".equals(method) ? getRequest(reqName, param) : postRequest(reqName, param));
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                if (callResponse != null) {
                    callResponse.error(e);
                }
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                callResponse(response, callResponse);
            }
        });
    }
3.同步Post請求

在OkHttp中用Post方法向服務器發送一個請求體時,請求體需要是一個RequestBody。這個請求體可以是:

  • key-value:鍵值對類型
  • String:字符串類型
  • Form:類似於Html的表單數據提交
  • Stream:流類型
  • File:文件類型

在這裏針對第一種方式做說明。

首先創建post方式的Request對象:

    /**
     * 獲取 post方式 Request 對象
     *
     * @param reqName 接口名稱
     * @param param   參數
     * @return Request 對象
     */
    private Request postRequest(String reqName, Map<String, String> param) {
//        創建Request對象,設置一個url地址,設置請求方式。
        FormBody.Builder mBuild = new FormBody.Builder();
        for (Map.Entry<String, String> entry : param.entrySet()) {
            mBuild.add(entry.getKey(), entry.getValue());
        }
        RequestBody requestBody = mBuild.build();
        return new Request.Builder()
                .url(BASE_URL + reqName)
                .post(requestBody)
                .build();
    }

然後創建一個call對象,並使用同步方法發起請求:

    /**
     * 同步請求
     *
     * @param method       請求方式  get or post
     * @param reqName      接口名稱
     * @param param        參數
     * @param callResponse 請求回調
     */
    public void execute(String method, String reqName, Map<String, String> param, final CallResponse callResponse) {
        final Call call = client.newCall("get".equals(method) ? getRequest(reqName, param) : postRequest(reqName, param));
        //同步調用會阻塞主線程,這邊在子線程進行,這裏就直接使用線程了,如果項目中使用最好是用線程池
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Response response = call.execute();
                    callResponse(response, callResponse);
                } catch (Exception e) {
                    e.printStackTrace();
                    if (callResponse != null) {
                        callResponse.error(e);
                    }
                }
            }
        }).start();
    }

請求數據方式跟get一樣,參考get的寫法。

4.異步Post請求

異步post請求只是在發起請求那與同步有區別,之前的步驟都一致:

    /**
     * 異步請求
     *
     * @param method       請求方式  get or post
     * @param reqName      接口名稱
     * @param param        參數
     * @param callResponse 請求回調
     */
    public void enqueue(String method, String reqName, Map<String, String> param, final CallResponse callResponse) {
        final Call call = client.newCall("get".equals(method) ? getRequest(reqName, param) : postRequest(reqName, param));
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                if (callResponse != null) {
                    callResponse.error(e);
                }
            }

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

數據回調接口:

public interface CallResponse {
    /**
     * 接口請求成功
     */
    void success(String data);

    /**
     * 接口請求失敗
     */
    void fail(String msg);

    /**
     * 接口請求報錯
     */
    void error(Exception e);

}

ApiWork 數據接口請求類:

public class ApiWork {
    private static ApiWork instance = null;
    private ApiWork() {
    }
    public static ApiWork getInstance() {
        synchronized (ApiWork.class) {
            if (instance == null) {
                instance = new ApiWork();
            }
        }
        return instance;
    }

    public void getinfolist(String nowpage,String pagesize,CallResponse callResponse){
        Map<String,String> param=new HashMap<>(2);
        param.put("nowpage",nowpage);
        param.put("pagesize",pagesize);
        OkHttpProxy.getInstance().execute("get","info/testokhttp",param,callResponse);
    }
}

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