OkHttp的使用

1.介紹

OkHttp是由Square公司開發的一個用於Android和Java的HTTP/HTTP2的網絡請求庫,它的一些優點:

  • 在HTTP2的支持下,如果請求的host是同一個時,允許這些請求共用一個socket
  • 使用連接池減少網絡延遲,如果HTTP2不可用
  • 透明的GZIP壓縮,減少數據流量
  • 緩存網絡響應,避免重複網絡請求

除此之外,還可以自動從常見網絡錯誤中恢復過來。如果服務器有多個IP地址,當第一次連接失敗,會自動重試其他IP地址。請求和響應使用建造者模式,使用簡便。
GitHub地址爲 https://github.com/square/okhttp

2.使用

添加依賴

implementation("com.squareup.okhttp3:okhttp:4.2.2")
2.1 GET同步請求

調用execute()方法執行同步請求

private void loadDataSync() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            String url = "http://publicobject.com/helloworld.txt";
            //構建一個GET請求
            Request request = new Request.Builder().get().url(url).build();
            //創建一個OkHttpClient
            OkHttpClient okHttpClient = new OkHttpClient();
            try {
                //執行請求獲取結果
                Response response = okHttpClient.newCall(request).execute();
                //得到響應字符串
                String string = response.body().string();

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }).start();
}
2.2 GET異步請求

調用enqueue()方法執行異步請求,請求會在內部的線程池進行,請求結果通過回調Callback返回,回調方法都在子線程執行,所以不能直接更新ui。

private void loadDataAsync() {
    String url = "http://publicobject.com/helloworld.txt";
    Request request = new Request.Builder().get().url(url).build();
    OkHttpClient okHttpClient = new OkHttpClient();
    okHttpClient.newCall(request).enqueue(new Callback() {

        @Override
        public void onFailure(Call call, IOException e) {

        }
        //在子線程中回調
        @Override
        public void onResponse(Call call, Response response) throws IOException {
            String result = response.body().string();
            //獲取字節數組
            byte[] bytes = response.body().bytes();
            //獲取InputStream
            InputStream inputStream = response.body().byteStream();
        }
    });
}

另外response.body().string()方法只能調用一次,這只因爲第一次調用string()時會關閉I/O流並清空Buffer,這樣做是爲了防止無用的,多的I/O操作。可以看一下方法的源碼

public final String string() throws IOException {
    try (BufferedSource source = source()) {
      Charset charset = Util.bomAwareCharset(source, charset());
      return source.readString(charset);
    }
}
2.3 POST提交表單

使用FromBody.Builder構建一個提交表單的請求體,添加鍵值對。

private void postForm() {
    OkHttpClient client = new OkHttpClient();
    //創建提交表單的請求體,添加鍵值對
    RequestBody formBody = new FormBody.Builder()
            .add("search", "Uncle")
            .build();
    //創建POST請求
    Request request = new Request.Builder()
            .url("https://en.wikipedia.org/w/index.php")
            .post(formBody)
            .build();
    //異步請求
    client.newCall(request).enqueue(mPostFormCallback);
}

private Callback mPostFormCallback = new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {

    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        //獲取返回的HTML字符串
        final String result = response.body().string();
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                //使用webView加載
                //mWebView.loadData(result, "text/html", "utf-8");
            }
        });
    }
};
2.4 POST提交JSON

只需要創建請求體時指定媒體類型爲"application/json"即可

private void postJson() {
    String json = "";
    String url = "";
    OkHttpClient okHttpClient = new OkHttpClient();
    MediaType mediaType = MediaType.parse("application/json; charset=utf-8");
    RequestBody requestBody = RequestBody.create(mediaType, json);
    Request request = new Request.Builder()
            .url(url)
            .post(requestBody)
            .build();
    okHttpClient.newCall(request).enqueue(mPostFormCallback);
}
2.5 緩存

緩存的配置只需要在創建OkHttp時傳入一個Cache,指定緩存目錄和大小即可。

int cacheSize = 10 * 1024 * 1024;
Cache cache = new Cache(cacheDir, cacheSize);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
        .cache(cache)
        .build();

3 攔截器

攔截器機制能夠監控、重寫、重試請求。根據攔截的位置可分2種,一種是應用攔截器,攔截應用層與OkHttp之間的網絡請求和響應;另一種是網絡攔截器,攔截OkHttp與網絡層之間的網絡請求和響應。
定義一個攔截器LoggingInterceptor,在攔截方法intercept中,獲取網絡請求。

public class LoggingInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        //獲取請求
        Request request = chain.request();
        long t1 = System.nanoTime();
        //打印請求的url,連接,請求頭
        Log.d("TAG", "sending request: " +
                request.url() + chain.connection() + request.headers());
        //執行請求,返回結果
        Response response = chain.proceed(request);
        long t2 = System.nanoTime();
        //打印執行請求的url,響應頭,消耗時間
        Log.d("TAG", "received response: " +
                response.request().url() + response.headers() + (t2 - t1));
        return response;
    }
}

然後將這個攔截器設置爲應用攔截器,通過addInterceptor方法將攔截器設置給OkHttpClient。

OkHttpClient okHttpClient = new OkHttpClient.Builder()
    .addInterceptor(new LoggingInterceptor())
    .build();

使用addNetworkInterceptor設置網絡攔截器

 OkHttpClient okHttpClient = new OkHttpClient.Builder()
    .addNetworkInterceptor(new LoggingInterceptor())
    .build();

攔截器可以添加移除或者替換網絡請求和響應頭裏面的字段,同時也可以加工請求體和響應體,比如當返回網絡響應時,在響應頭裏並沒有配置Cache-Control來控制緩存,但我們又想讓這個響應緩存起來,這時可以配置一下網絡攔截器攔截網絡響應,在響應頭裏添加這個字段。

private static final Interceptor REWERITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Response originalResponse = chain.proceed(chain.request());
        CacheControl.Builder builder = new CacheControl.Builder()
                .maxAge(5, TimeUnit.MINUTES);
        return originalResponse.newBuilder()
                .header("Cache-Control", builder.build().toString())
                .build();
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章