OkHttp3 使用詳解


一,簡介

OkHttp 是一個高效的 HTTP 客戶端,具有非常多的優勢:

  1. 能夠高效的執行 http,數據加載速度更快,更省流量
  2. 支持 GZIP 壓縮,提升速度,節省流量
  3. 緩存響應數據,避免了重復的網絡請求
  4. 使用簡單,支持同步阻塞調用和帶回調的異步調用

OkHttp 支持 Android2.3 以上,JDK1.7 以上。

官網地址:https://square.github.io/okhttp/
github地址:https://github.com/square/okhttp

二,基本用法

添加 OkHttp 依賴
compile 'com.squareup.okhttp3:okhttp:(insert latest version)'
最新的版本號可以在官網和github上找到

1. Get 請求

使用 OkHttp 進行 Get 請求只需要四個步驟

  1. 新建 OkHttpClient對象
  2. 構造 Request 對象
  3. 將 Request 對象封裝為 Call
  4. 通過 Call 來執行同步或異步請求
        String url = "http://www.xxxx.com";
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(url)
                .get()  //默認為GET請求,可以不寫
                .build();
       final Call call = client.newCall(request);

1.1 Get 同步請求

通過 call.excute() 方法來提交同步請求,這種方式會阻塞線程,而為了避免 ANR 異常,Android3.0 之后已經不允許在主線程中訪問網絡了
所以 OkHttp 的同步 get 請求需要開啟一個子線程:

      new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Response response = call.execute();
                    Log.d(TAG, response.body().toString());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();

1.2 Get 異步請求

通過 call.enqueue(Callback)方法來提交異步請求

        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.d(TAG, "onFailure: " + e);
            }
 
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                Log.d(TAG, "OnResponse: " + response.body().toString());
            }
        });

2. Post 請求

創建 Post 請求的方式與 Get 方法類似,只是需要增加一個步驟,構造出一個請求參數對象RequestBody ,用於攜帶我們需要提交的數據。(下面均以 Post 的異步請求為例,Post 同步請求只需將 call.enqueue() 替換成 call.execute() 即可)

public Builder post(RequestBody body)

Request 的 post 方法所接收的參數是 RequestBody 對象,所以只要是 RequestBody 類及其子類都可以當做參數傳入。

RequestBody是一個抽象類,常用的 RequestBody 實現類有這么幾種:

2.1 FormBody

FormBody是RequestBody的實現類,用於表單方式的請求

        OkHttpClient client = new OkHttpClient();
        //創建表單請求參數
        FormBody.Builder builder = new FormBody.Builder();
        builder.add("name", "zhangsan");
        builder.add("age", "18");
        FormBody formBody = builder.build();
        Request request = new Request.Builder()
                .url(url)
                .post(formBody)
                .build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            }
            @Override
            public void onResponse(Call call, Response response) throws IOException {
            }
        });

2.2 RequestBody.create(...)

RequestBody 是一個抽象類,我們不能直接使用它,但是可以通過調用它的靜態create方法來獲取一個RequestBody對象,該方法會創建並返回一個 RequestBody 的匿名內部類實例
查看一下 RequestBody 類,發現它有這樣幾個 create 方法。

其中前三個方法最終調用的都是第四個方法,所以我們可以具體看一下最后兩個方法的具體實現

  /** Returns a new request body that transmits {@code content}. */
  public static RequestBody create(final @Nullable MediaType contentType, final byte[] content,
      final int offset, final int byteCount) {
    if (content == null) throw new NullPointerException("content == null");
    Util.checkOffsetAndCount(content.length, offset, byteCount);
    return new RequestBody() {
      @Override public @Nullable MediaType contentType() {
        return contentType;
      }
      @Override public long contentLength() {
        return byteCount;
      }
      @Override public void writeTo(BufferedSink sink) throws IOException {
        sink.write(content, offset, byteCount);
      }
    };
  }
  /** Returns a new request body that transmits the content of {@code file}. */
  public static RequestBody create(final @Nullable MediaType contentType, final File file) {
    if (file == null) throw new NullPointerException("content == null");
    return new RequestBody() {
      @Override public @Nullable MediaType contentType() {
        return contentType;
      }
      @Override public long contentLength() {
        return file.length();
      }
      @Override public void writeTo(BufferedSink sink) throws IOException {
        Source source = null;
        try {
          source = Okio.source(file);
          sink.writeAll(source);
        } finally {
          Util.closeQuietly(source);
        }
      }
    };
  }

這里多解釋一下
Content-Type(MediaType),即是Internet Media Type,互聯網媒體類型;也叫做MIME類型,在Http協議消息頭中,使用Content-Type來表示具體請求中的媒體類型信息。用於定義網絡文件的類型和網頁的編碼,決定文件接收方將以什么形式、什么編碼讀取這個文件。常見的媒體格式類型有:

  • text/html:HTML格式
  • text/pain:純文本格式
  • image/jpeg:jpg圖片格式
  • application/json:JSON數據格式
  • application/octet-stream:二進制流數據(如常見的文件下載)
  • application/x-www-form-urlencoded:form表單encType屬性的默認格式,表單數據將以key/value的形式發送到服務端
  • multipart/form-data:表單上傳文件的格式

使用 create 方法可以用來用於上傳 String 和 File 對象,具體實現如下:
上傳JSON字符串:

        OkHttpClient client = new OkHttpClient();
        //指定當前請求的 contentType 為 json 數據
        MediaType JSON = MediaType.parse("application/json; charset=utf-8");
        String jsonStr = "{\"name\":\"zhangsan\",\"age\":\"20\"}";
        Request request = new Request.Builder()
                .url(url)
                .post(RequestBody.create(JSON, jsonStr))
                .build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            }
            @Override
            public void onResponse(Call call, Response response) throws IOException {
            }
        });

上傳文件:

        OkHttpClient client = new OkHttpClient();
        File file = new File(filePath);
        Request request = new Request.Builder()
                .url(url)
                .post(RequestBody.create(MediaType.parse("application/octet-stream"), file))
                .build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            }
            @Override
            public void onResponse(Call call, Response response) throws IOException {
            }
        });

2.3 使用MultipartBody同時上傳多種類型數據

多文件和鍵值對同時上傳

        OkHttpClient client = new OkHttpClient();
        MultipartBody multipartBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("name", "zhangsan")
                .addFormDataPart("age", "20")
                .addFormDataPart("file", file.getName(),
                        RequestBody.create(MediaType.parse("application/octet-stream"), file))
                .build();
        
        Request request = new Request.Builder()
                .url(url)
                .post(multipartBody)
                .build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            }
            @Override
            public void onResponse(Call call, Response response) throws IOException {
            }
        });

3. Call 請求器

OkHttp 客戶端負責接收應用程序發出的請求,並且從服務器獲取響應返回給應用程序。理論聽起來十分簡單,但是在實踐中往往會出現很多意想不到的問題。
通過配置 OkHttpClient,可以配置重寫請求、重寫響應、跟蹤請求、重試請求等多種操作,這樣一來你發送的一個簡單請求可能就會變成需要發送多個請求以及接收多個響應后才能獲得想要的響應。OkHttp 將這些多次的中間請求和響應任務建模成了一個 Call 對象,但是通常情況下中間請求及響應工作不會很多,令人欣慰的是,無論發生URL重定向還是因為服務器出現問題而向一個備用IP地址再次發送請求的情況,你的代碼都將正常運行。
執行Call有兩種方式:

  • 同步:請求和處理響應發生在同一線程。並且此線程會在響應返回之前會一直被堵塞。
  • 異步:請求和處理響應發生在不同線程。將發送請求操作發生在一個線程,並且通過回調的方式在其他線程進行處理響應。(一般在子線程發送請求,主線程處理響應)。

Calls可以在任何線程被取消。當這個Call尚未執行結束時,執行取消操作將會直接導致此Call失敗!當一個Call被取消時,無論是寫入請求主體或者讀取響應主體的代碼操作,都會拋出一個IOException異常。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM