1. 程式人生 > 其它 >25、Android--OkHttp

25、Android--OkHttp

OkHttp

OkHttp是一個優秀的網路請求框架,在使用需要新增相應的依賴:

implementation "com.squareup.okhttp3:okhttp:3.11.0"

還有請求網路的許可權:

GET請求

使用OkHttp進行Get請求只需要四步即可完成。

// 構建OkHttpClient物件
OkHttpClient client = new OkHttpClient();
// 構造Request物件
Request request = new Request.Builder()
      .url("www.baidu.com")
      .get()
      .build();
//將Request封裝為Call
Call call = client.newCall(request);

最後,根據需要呼叫同步或者非同步請求方法即可

同步呼叫

//同步呼叫,返回Response,會丟擲IO異常
Response response = call.execute();

非同步呼叫

//非同步呼叫,並設定回撥函式
call.enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        Toast.makeText(OkHttpActivity.this, "get failed", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onResponse(Call call, final Response response) throws IOException {
        final String res = response.body().string();
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                contentTv.setText(res);
            }
        });
    }
});

在使用OkHttp需要注意:

同步呼叫會阻塞主執行緒,一般不適用
非同步呼叫的回撥函式是在子執行緒,需要藉助於 runOnUiThread() 方法或者Handler來處理。

POST提交鍵值對

使用OkHttp進行Post請求和進行Get請求很類似,只需要五步即可完成。

// 構建OkHttpClient物件
OkHttpClient client = new OkHttpClient();
// 構建FormBody傳入引數
FormBody formBody = new FormBody.Builder()
    .add("username", "admin")
    .add("password", "admin")
    .build();
// 構造Request物件,將FormBody作為Post方法的引數傳入
Request request = new Request.Builder()
    .url("https:www.baidu.com")
    .post(formBody)
    .build();
//將Request封裝為Call
Call call = client.newCall(request);

最後,呼叫請求,重寫回調方法:

call.enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        Toast.makeText(OkHttpActivity.this, "Post Failed", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        final String res = response.body().string();
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                contentTv.setText(res);
            }
        });
    }
});

POST提交字串

POST提交字串就需要使用RequestBody,其中FormBody是RequestBody的子類。

// 構建OkHttpClient物件
OkHttpClient client = new OkHttpClient();
// 構建FormBody傳入引數
RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain;charset=utf-8"), "1111111111111111");
// 構造Request物件,將FormBody作為Post方法的引數傳入
Request request = new Request.Builder()
        .url("www.baidu.com")
        .post(requestBody)
        .build();
//將Request封裝為Call
Call call = client.newCall(request);
call.enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
    }

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

上面的MediaType我們指定傳輸的是純文字,而且編碼方式是utf-8,通過上面的方式我們就可以向服務端傳送json字串。

POST上傳檔案

這裡我們以上傳一張圖片為例,演示OkHttp上傳單檔案:

OkHttpClient okHttpClient = new OkHttpClient();
File file = new File(Environment.getExternalStorageDirectory(), "1.png");
RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"),file);
Request request = new Request.Builder()
        .url("www.baidu.com")
        .post(requestBody)
        .build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
    }

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

如果是多檔案上傳,可以使用表單的方式來提交:

List<String> fileNames = new ArrayList<>();
fileNames.add(Environment.getExternalStorageState() + "/1.png");
fileNames.add(Environment.getExternalStorageState() + "/2.png");
OkHttpClient okHttpClient = new OkHttpClient();
MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
for (String fileName : fileNames) {
    File file = new File(fileName);
    builder.addFormDataPart("files", file.getName(), RequestBody.create(
            MediaType.parse("multipart/form-data"), file));
}
MultipartBody multipartBody = builder.build();
Request request = new Request.Builder()
        .url("www.baidu.com")
        .post(multipartBody)
        .build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
    }

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

POST提交表單

其中,MultipartBody是RequestBody的子類,提交表單需要使用它來構建RequestBody。

File file = new File(Environment.getExternalStorageDirectory(), "1.png");
OkHttpClient okHttpClient = new OkHttpClient();
RequestBody requestBody = new MultipartBody.Builder()
        .setType(MultipartBody.FORM)
        .addFormDataPart("username", "admin")
        .addFormDataPart("password", "admin")
        .addFormDataPart("file", file.getName(),
                RequestBody.create(MediaType.parse("application/octet-stream"), file))
        .build();
Request request = new Request.Builder()
        .url("www.baidu.com")
        .post(requestBody)
        .build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
    }

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

GET下載檔案

下面將演示OkHttp使用GET請求下載檔案的例項:

OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
        .url("www.baidu.com/1.png")
        .get()
        .build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        InputStream inputStream = response.body().byteStream();
        int len;
        File file  = new File(Environment.getExternalStorageDirectory(), "1.png");
        FileOutputStream fos = new FileOutputStream(file);
        byte[] buf = new byte[128];

        while ((len = inputStream.read(buf)) != -1){
            fos.write(buf, 0, len);
        }
        fos.flush();
        fos.close();
        inputStream.close();
    }
});

可以通過流的讀取來實現檔案的上傳和下載進度顯示。

OkHttp攔截器

OkHttp的攔截器有五種內建的,除此之外還可以自定義攔截器。

  • retryAndFollowUpInterceptor:重試和重定向攔截器,主要負責網路失敗重連。
  • BridgeInterceptor:主要負責新增交易請求頭。
  • CacheInterceptor:快取攔截器,主要負責攔截快取。
  • ConnectInterceptor:網路連線攔截器,主要負責正式開啟http請求。
  • CallServerInterceptor:負責傳送網路請求和讀取網路響應

這裡主要介紹使用自定義日誌攔截器來列印Logger資訊。

1)建立HttpLogger類實現HttpLoggingInterceptor.Logger

public class HttpLogger implements HttpLoggingInterceptor.Logger {
    @Override
    public void log(String message) {
        Log.e("HttpLogInfo", message);
    }
}

2) 使用OkHttpClient.Builder新增攔截器

// Add Logger Interceptor
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLogger());
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BASIC);
clientBuilder.addNetworkInterceptor(loggingInterceptor);

這樣,就可以在請求網路的時候看到OkHttp的日誌資訊。

關於OkHttp還有很多內容,這裡只是簡單的介紹使用。