1. 程式人生 > >Android——使用OkHttp(含各種請求方法)

Android——使用OkHttp(含各種請求方法)

支援 SPDY ,共享同一個 Socket 來處理同一個伺服器的所有請求
1、如果 SPDY 不可用,則通過連線池來減少請求延時
2、無縫的支援GZIP來減少資料流量
3、快取響應資料來減少重複的網路請求

OkHttp 處理了很多網路疑難雜症:會從很多常用的連線問題中自動恢復。

一、測試使用我們的OKHttp第三方庫

1.第一步我們需要去建立一個 OKHttpClient 物件

OkHttpClient okHttpClient = new OkHttpClient();

2.下一步我們還需要一個 Request 物件,她可以已如下方式被建立

Request request
= new Request.Builder() .url(requestUrl) .build();

requestUrl是一個字串變數,表示這個URL是為了JSON請求(The requestUrl is a String variable representing the Url for the JSON request.)

3.再下一步我們需要例項化一個 Call 物件

Call call  = okHttpClient.newCall(request);

Call物件會取走我們的 okHttpClient物件 和 我們的 request物件。

4.在例項化Call物件後,我們現在可以 Execute(執行)它。Executing一個Call後將會返回一個 Response,

並且會丟擲一個 IOException的異常,這就是為什麼們會用一個try,catch塊包裹她。

try{
        Response response = call.execute();
}catch (IOException e){
        e.printStackTrace();
}

5.執行完我們的Call後,我們需要通過使用 response.isSuccessful()來檢查Call物件是否執行成功,

通過response.isSuccessful()的返回值為true或者是false來判斷。
這我們僅僅是一個測試,如果Call成功的話,我們將會通過Log來列印我們的response。

try{
        Response response = call.execute();
        if(response.isSuccessful()){
                //The call was successful.print it to the log
                Log.v("OKHttp",response.body().string());
        }
    }catch(IOException e){
        e.printStackTrace();
}

6.測試Code!

這裡寫圖片描述
這是新手一個常見的錯誤。在Android中不允許任何網路的互動在主執行緒中進行。
It disallows it to force developers to use asynchronous callbacks.
但是現在,我們的程式碼看起來看起來十分的號好!下面我們來看看如何修復這個問題。

7.Fix issue

為了修補這個問題,我們只需要讓我們的Call執行在非主執行緒內,
所以利用一個 asynchronous callback(非同步的callBack)。

讓我們call非同步的方法是通過呼叫我們Call物件的 enqueue()方法。

call.enqueue(new Callback()) {

        @Override
        public void onFailure( Request request, IOException e ) {

        }

        @Override
        public void OnResponse( Response response) throws IOException {
                try {
                        if(response.isSuccessful()){
                            //The call was successful. print it to the log
                            log.v("OKHttp",response.body.string());
                         }
                }catch (IOException e) {
                    e.printStackTrace();
                }
        }
});

8.在我們再次執行我們的code之前,我們還需要再改一改。如果我們想要現在執行她,我們可能還會接收到錯誤的提示,

因為我們應用的程式沒有得到相應的相應的網路許可權。所以我們需要再AndroidManifest.xml中新增應用許可權。

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

9.當我們執行完code後,我們將接受到如下的log輸出:

這裡寫圖片描述

10.

This means, we are now able to execute asynchronous network calls and use the data inside the callback method, when it is ready!

onResponse回撥的引數是response,一般情況下,

比如我們希望獲得返回的字串,可以通過response.body().string()獲取;
如果希望獲得返回的二進位制位元組陣列,則呼叫response.body().bytes();
如果你想拿到返回的inputStream,則呼叫response.body().byteStream()

二、請求方法介紹

1、HTTP請求方法

  • 同步GET請求
private final OkHttpClient client = new OkHttpClient();  

public void run() throws Exception {  
    Request request = new Request.Builder()  
            .url("http://publicobject.com/helloworld.txt")  
            .build();  
    Response response = client.newCall(request).execute();  
    if (!response.isSuccessful())  
        throw new IOException("Unexpected code " + response);  
    Headers responseHeaders = response.headers();  
    for (int i = 0; i < responseHeaders.size(); i++) {  
        System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));  
    }  
    System.out.println(response.body().string());  
}  

Response類的string()方法會把文件的所有內容載入到記憶體,適用於小文件,
對應大於1M的文件,應使用流()的方式獲取。
response.body().byteStream()

  • 非同步GET請求
private final OkHttpClient client = new OkHttpClient();  

public void run() throws Exception {  
    Request request = new Request.Builder()  
            .url("http://publicobject.com/helloworld.txt")  
            .build();  
    client.newCall(request).enqueue(new Callback() {  
        @Override  
        public void onFailure(Request request, IOException e) {  
            e.printStackTrace();  
        }  

        @Override  
        public void onResponse(Response response) throws IOException {  
            if (!response.isSuccessful()) {  
                throw new IOException("Unexpected code " + response);  
            }  
            Headers responseHeaders = response.headers();  
            for (int i = 0; i < responseHeaders.size(); i++) {  
                System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));  
            }  

            System.out.println(response.body().string());  
        }  
    });  
}  

讀取響應會阻塞當前執行緒,所以發起請求是在主執行緒,回撥的內容在非主執行緒中。

  • POST方式提交字串
private static final MediaType MEDIA_TYPE_MARKDOWN  
        = MediaType.parse("text/x-markdown; charset=utf-8");  

private final OkHttpClient client = new OkHttpClient();  

public void run() throws Exception {  
    String postBody = ""  
            + "Releases\n"  
            + "--------\n"  
            + "\n"  
            + " * _1.0_ May 6, 2013\n"  
            + " * _1.1_ June 15, 2013\n"  
            + " * _1.2_ August 11, 2013\n";  

    Request request = new Request.Builder()  
            .url("https://api.github.com/markdown/raw")  
            .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, postBody))  
            .build();  

    Response response = client.newCall(request).execute();  
    if (!response.isSuccessful())   
        throw new IOException("Unexpected code " + response);  

    System.out.println(response.body().string());  
}  

因為整個請求體都在記憶體中,應避擴音交1M以上的檔案。

  • POST方式提交流
private final OkHttpClient client = new OkHttpClient();  

public void run() throws Exception {  
    RequestBody requestBody = new RequestBody() {  
        @Override  
        public MediaType contentType() {  
            return MEDIA_TYPE_MARKDOWN;  
        }  

        @Override  
        public void writeTo(BufferedSink sink) throws IOException {  
            sink.writeUtf8("Numbers\n");  
            sink.writeUtf8("-------\n");  
            for (int i = 2; i <= 997; i++) {  
                sink.writeUtf8(String.format(" * %s = %s\n", i, factor(i)));  
            }  
        }  

        private String factor(int n) {  
            for (int i = 2; i < n; i++) {  
                int x = n / i;  
                if (x * i == n) return factor(x) + " × " + i;  
            }  
            return Integer.toString(n);  
        }  
    };  

    Request request = new Request.Builder()  
            .url("https://api.github.com/markdown/raw")  
            .post(requestBody)  
            .build();  

    Response response = client.newCall(request).execute();  
    if (!response.isSuccessful())   
        throw new IOException("Unexpected code " + response);  

    System.out.println(response.body().string());  
}  

使用Okio框架以流的形式將內容寫入,這種方式不會出現記憶體溢位問題。

  • POST方式提交檔案
public static final MediaType MEDIA_TYPE_MARKDOWN  
        = MediaType.parse("text/x-markdown; charset=utf-8");  

private final OkHttpClient client = new OkHttpClient();  

public void run() throws Exception {  
    File file = new File("README.md");  

    Request request = new Request.Builder()  
            .url("https://api.github.com/markdown/raw")  
            .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file))  
            .build();  

    Response response = client.newCall(request).execute();  
    if (!response.isSuccessful())   
        throw new IOException("Unexpected code " + response);  

    System.out.println(response.body().string());  
}  
  • POST方式提交表單
private final OkHttpClient client = new OkHttpClient();  

public void run() throws Exception {  
    RequestBody formBody = new FormEncodingBuilder()  
            .add("search", "Jurassic Park")  
            .build();  
    Request request = new Request.Builder()  
            .url("https://en.wikipedia.org/w/index.php")  
            .post(formBody)  
            .build();  

    Response response = client.newCall(request).execute();  
    if (!response.isSuccessful())   
        throw new IOException("Unexpected code " + response);  

    System.out.println(response.body().string());  
}  

表單的每個Names-Values都進行了URL編碼。如果伺服器端介面未進行URL編碼,可定製個 FormBuilder。

  • 檔案上傳(相容html檔案上傳)
private static final String IMGUR_CLIENT_ID = "...";  
private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");  

private final OkHttpClient client = new OkHttpClient();  

public void run() throws Exception {  
    // Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image  
    RequestBody requestBody = new MultipartBuilder()  
            .type(MultipartBuilder.FORM)  
            .addPart(  
                    Headers.of("Content-Disposition", "form-data; name=\"title\""),  
                    RequestBody.create(null, "Square Logo"))  
            .addPart(  
                    Headers.of("Content-Disposition", "form-data; name=\"image\""),  
                    RequestBody.create(MEDIA_TYPE_PNG, new File("website/static/logo-square.png")))  
            .build();  

    Request request = new Request.Builder()  
            .header("Authorization", "Client-ID " + IMGUR_CLIENT_ID)  
            .url("https://api.imgur.com/3/image")  
            .post(requestBody)  
            .build();  

    Response response = client.newCall(request).execute();  
    if (!response.isSuccessful())   
        throw new IOException("Unexpected code " + response);  
    System.out.println(response.body().string());  
}