天天看點

OKHttp的基本使用和簡單封裝

1.寫在前面:

  網絡請求架構層出不窮,像google的volley,xutils等等。聽說Okhttp性能很高,最近寫新項目,決定用Okhttp來嘗試一下(原諒我是小白,第一次使用,以前還是用volley),以此來記錄一下自己的心得。

2.首先來介紹一下Okhttp:

  Okhttp出自鼎鼎大名的Square,官方github位址:https://github.com/square/okhttp;它基本包含所有常用的網絡請求,同步、異步的get、post請求,檔案上傳下載下傳等等,廢話不說,直接進入教程

3.Okhttp的使用:

1)首先添加依賴:

Download the latest JAR or grab via Maven:
<dependency>
  <groupId>com.squareup.okhttp3</groupId>
  <artifactId>okhttp</artifactId>
  <version>3.6.0</version>
</dependency>
or Gradle:
compile 'com.squareup.okhttp3:okhttp:3.6.0'
           

還在用eclipse的童鞋也可以下載下傳jar使用,不過抓緊時間換Android Studio吧;

2)同時别忘了添加添加網絡權限:

3)開始編寫代碼:

http同步get請求:

/**
     * 同步的Get請求
     *
     * @param url
     * @return responseStr
     * @throws IOException
     */
    public static String getSync(String url) throws IOException {
        // 建立OKHttpClient對象
        OkHttpClient okHttpClient = new OkHttpClient();
        // 建立一個Request
        final Request request = new Request.Builder()
                .url(url)
                .build();
        Call call = okHttpClient.newCall(request);
        // 傳回值為response
        Response response = call.execute();
        // 将response轉化成String
        String responseStr = response.body().string();
        return responseStr;
    }
           

  OKHttp請求成功的傳回值為Response ,一般可以通過response.body().string()擷取傳回的字元串;也可以通過response.body().bytes()擷取傳回的二進制位元組數組;也可以通過response.body().byteStream()擷取傳回的inputStream。

  

http異步get請求:

/**
     * 異步的Get請求
     *
     * @param url url
     */
    public static void getAsyn(String url) {
        // 建立OKHttpClient對象
        OkHttpClient okHttpClient = new OkHttpClient();
        // 建立一個Request
        final Request request = new Request.Builder()
                .url(url)
                .build();
        Call call = okHttpClient.newCall(request);
        // 請求加入排程
        call.enqueue(new Callback() {
            // 請求失敗的回調
            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
            }

            // 請求成功的回調
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                // 将response轉化成String
                String responseStr = response.body().string();
            }
        });
    }
           

  同上OKHttp請求成功的傳回值為Response ,一般可以通過response.body().string()擷取傳回的字元串;值得注意的是它的傳回值是在子線程中而不是UI線程,想要在UI線程中使用,還需要使用handler等,例如:

// 請求成功的回調
    @Override
    public void onResponse(Call call, Response response) throws IOException {
        // 将response轉化成String
        String responseStr = response.body().string();
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getApplicationContext(), responseStr,
                    Toast.LENGTH_SHORT).show();
                    }
            }
    }
           

  這樣http的異步get請求就完成了,如果每次請求都寫如此多的代碼而且傳回值還不是在UI線程,那每發送一次請求都很麻煩,看到這,你一定會想到封裝,沒錯,将OKHttp封裝成一個工具類,每次使用直接去調用就簡單多了,在本文最後我也會提供我自己對OKHttp的簡單封裝,供大家參考。

http同步post請求:

/**
     * 同步的Post請求
     *
     * @param url    url
     * @param params params
     * @return responseStr
     * @throws IOException
     */
    public static String postSync(String url, Map<String, String> params) 
        throws IOException {
        // RequestBody
        RequestBody requestBody;
        if (params == null) {
            params = new HashMap<>();
        }
        // 建立OKHttpClient對象
        OkHttpClient okHttpClient = new OkHttpClient();
        FormBody.Builder builder = new FormBody.Builder();
        /**
         * 在這對添加的參數進行周遊
         */
        for (Map.Entry<String, String> map : params.entrySet()) {
            String key = map.getKey();
            String value;
            /**
             * 判斷值是否是空的
             */
            if (map.getValue() == null) {
                value = "";
            } else {
                value = map.getValue();
            }
            /**
             * 把key和value添加到formBody中
             */
            builder.add(key, value);
        }
        requestBody = builder.build();
        // 建立一個Request
        final Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
        Call call = okHttpClient.newCall(request);
        // 傳回值為response
        Response response = call.execute();
        // 将response轉化成String
        String responseStr = response.body().string();
        return responseStr;
    }
           

   大家知道,發送post請求時,參數是包含在請求體中的,是以我們去構造RequestBody,最後完成我們Request的構造。

http異步post請求:

/**
     * 異步的Post請求
     *
     * @param url    url
     * @param params params
     * @return responseStr
     */
    public static void postAsyn(String url, Map<String, String> params) {
        // RequestBody
        RequestBody requestBody;
        if (params == null) {
            params = new HashMap<>();
        }
        // 建立OKHttpClient對象
        OkHttpClient okHttpClient = new OkHttpClient();
        FormBody.Builder builder = new FormBody.Builder();
        /**
         * 在這對添加的參數進行周遊
         */
        for (Map.Entry<String, String> map : params.entrySet()) {
            String key = map.getKey();
            String value;
            /**
             * 判斷值是否是空的
             */
            if (map.getValue() == null) {
                value = "";
            } else {
                value = map.getValue();
            }
            /**
             * 把key和value添加到formBody中
             */
            builder.add(key, value);
        }
        requestBody = builder.build();
        // 建立一個Request
        final Request request = new Request.Builder()
                .url(url)
                .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 {
                // 将response轉化成String
                String responseStr = response.body().string();
            }
        });
    }
           

  以上是基于http的異步post請求,上面的例子添加的請求參數是Map,當然也可以添加其他類型的參數,如:

// post傳參(byte)
RequestBody byteBody = RequestBody.create(MediaType.parse("application/octet-stream; charset=utf-8"), mapToBytes(params));

mapToBytes(params)方法是将params轉化成byte
           

http的檔案上傳:

/**
     * 基于http的檔案上傳
     * 通過addFormDataPart可以添加多個上傳的檔案
     */
     public void uploadMultiFile() {
        // 建立OKHttpClient對象
        OkHttpClient okHttpClient = new OkHttpClient();
        File file = new File(Environment.getExternalStorageDirectory(), "pic.png");
        RequestBody fileBody = RequestBody.create
            (MediaType.parse("application/octet-stream"), file);
        RequestBody requestBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("image", "pic.png", fileBody)
                .build();
        Request request = new Request.Builder()
                .url("填寫url位址")
                .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 {

            }
        });
    }
           

http的檔案下載下傳:

/**
     * 基于http的下載下傳檔案請求
     *
     * @param downloadUrl 下載下傳位址
     */
    public static void downloadRequest(String downloadUrl) {
        // 建立OKHttpClient對象
        OkHttpClient okHttpClient = new OkHttpClient();
        Request request = new Request.Builder()
                .url(downloadUrl)
                .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 {
                // 下載下傳成功後執行的操作
            }
        });
    }
           

OKHttp的簡單封裝使用(NetRequest工具類):

  以上是OKHttp常用的請求,其他請求類似,不再重複。下面對OKHttp進行簡單的封裝,使其使用友善,不必每次都寫大量的重複方法,同時直接将傳回值Response傳遞到UI線程,将其封裝在OKHttp的工具類中,簡化代碼,下面直接貼代碼:

package com.guifa.okhttpdemo.http;

import android.os.Handler;
import android.os.Looper;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * Created by GuiFa on 2017/2/3.
 * 網絡請求工具類
 */
public class NetRequest {
    private static NetRequest netRequest;
    private static OkHttpClient okHttpClient; // OKHttp網絡請求
    private Handler mHandler;

    private NetRequest() {
        // 初始化okhttp 建立一個OKHttpClient對象,一個app裡最好執行個體化一個此對象
        okHttpClient = new OkHttpClient();
        okHttpClient.newBuilder()
                .connectTimeout(, TimeUnit.SECONDS)
                .readTimeout(, TimeUnit.SECONDS)
                .writeTimeout(, TimeUnit.SECONDS);
        mHandler = new Handler(Looper.getMainLooper());
    }

    /**
     * 單例模式  擷取NetRequest執行個體
     *
     * @return netRequest
     */
    private static NetRequest getInstance() {
        if (netRequest == null) {
            netRequest = new NetRequest();
        }
        return netRequest;
    }

    //-------------對外提供的方法Start--------------------------------

    /**
     * 建立網絡架構,擷取網絡資料,異步get請求(Form)
     *
     * @param url      url
     * @param params   key value
     * @param callBack data
     */
    public static void getFormRequest(String url, Map<String, String> params, DataCallBack callBack) {
        getInstance().inner_getFormAsync(url, params, callBack);
    }

    /**
     * 建立網絡架構,擷取網絡資料,異步post請求(Form)
     *
     * @param url      url
     * @param params   key value
     * @param callBack data
     */
    public static void postFormRequest(String url, Map<String, String> params, DataCallBack callBack) {
        getInstance().inner_postFormAsync(url, params, callBack);
    }

  /**
     * 建立網絡架構,擷取網絡資料,異步post請求(json)
     *
     * @param url      url
     * @param params   key value
     * @param callBack data
     */
    public static void postJsonRequest(String url, Map<String, String> params, DataCallBack callBack) {
        getInstance().inner_postJsonAsync(url, params, callBack);
    }
    //-------------對外提供的方法End--------------------------------

    /**
     * 異步get請求(Form),内部實作方法
     *
     * @param url    url
     * @param params key value
     */
    private void inner_getFormAsync(String url, Map<String, String> params, final DataCallBack callBack) {
        if (params == null) {
            params = new HashMap<>();
        }
        // 請求url(baseUrl+參數)
        final String doUrl = urlJoint(url, params);
        // 建立一個請求
        final Request request = new Request.Builder().url(doUrl).build();
        //執行請求獲得響應結果
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                deliverDataFailure(request, e, callBack);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response.isSuccessful()) { // 請求成功
                    //執行請求成功的操作
                    String result = response.body().string();
                    deliverDataSuccess(result, callBack);
                } else {
                    throw new IOException(response + "");
                }
            }
        });
    }

    /**
     * 異步post請求(Form),内部實作方法
     *
     * @param url      url
     * @param params   params
     * @param callBack callBack
     */
    private void inner_postFormAsync(String url, Map<String, String> params, final DataCallBack callBack) {
        RequestBody requestBody;
        if (params == null) {
            params = new HashMap<>();
        }
        FormBody.Builder builder = new FormBody.Builder();
        /**
         * 在這對添加的參數進行周遊
         */
        for (Map.Entry<String, String> map : params.entrySet()) {
            String key = map.getKey();
            String value;
            /**
             * 判斷值是否是空的
             */
            if (map.getValue() == null) {
                value = "";
            } else {
                value = map.getValue();
            }
            /**
             * 把key和value添加到formbody中
             */
            builder.add(key, value);
        }
        requestBody = builder.build();
        //結果傳回
        final Request request = new Request.Builder().url(url).post(requestBody).build();
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                deliverDataFailure(request, e, callBack);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response.isSuccessful()) { // 請求成功
                    //執行請求成功的操作
                    String result = response.body().string();
                    deliverDataSuccess(result, callBack);
                } else {
                    throw new IOException(response + "");
                }
            }
        });
    }

  /**
     * post請求傳json
     *
     * @param url      url
     * @param callBack 成功或失敗回調
     * @param params     params
     */
    private void inner_postJsonAsync(String url, Map<String, String> params,final DataCallBack callBack) {
        // 将map轉換成json,需要引入Gson包
        String mapToJson = new Gson().toJson(params);
        final Request request = buildJsonPostRequest(url, mapToJson);
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                deliverDataFailure(request, e, callBack);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response.isSuccessful()) { // 請求成功
                    //執行請求成功的操作
                    String result = response.body().string();
                    deliverDataSuccess(result, callBack);
                } else {
                    throw new IOException(response + "");
                }
            }
        });
    }

   /**
     * Json_POST請求參數
     *
     * @param url  url
     * @param json json
     * @return requestBody
     */
    private Request buildJsonPostRequest(String url, String json) {
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
        return new Request.Builder().url(url).post(requestBody).build();
    }

    /**
     * 分發失敗的時候調用
     *
     * @param request  request
     * @param e        e
     * @param callBack callBack
     */
    private void deliverDataFailure(final Request request, final IOException e, final DataCallBack callBack) {
        /**
         * 在這裡使用異步處理
         */
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                if (callBack != null) {
                    callBack.requestFailure(request, e);
                }
            }
        });
    }

    /**
     * 分發成功的時候調用
     *
     * @param result   result
     * @param callBack callBack
     */
    private void deliverDataSuccess(final String result, final DataCallBack callBack) {
        /**
         * 在這裡使用異步線程處理
         */
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                if (callBack != null) {
                    try {
                        callBack.requestSuccess(result);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }

    /**
     * 資料回調接口
     */
    public interface DataCallBack {

        void requestSuccess(String result) throws Exception;

        void requestFailure(Request request, IOException e);
    }

    /**
     * 拼接url和請求參數
     *
     * @param url    url
     * @param params key value
     * @return String url
     */
    private static String urlJoint(String url, Map<String, String> params) {
        StringBuilder endUrl = new StringBuilder(url);
        boolean isFirst = true;
        Set<Map.Entry<String, String>> entrySet = params.entrySet();
        for (Map.Entry<String, String> entry : entrySet) {
            if (isFirst && !url.contains("?")) {
                isFirst = false;
                endUrl.append("?");
            } else {
                endUrl.append("&");
            }
            endUrl.append(entry.getKey());
            endUrl.append("=");
            endUrl.append(entry.getValue());
        }
        return endUrl.toString();
    }
}
           

NetRequest工具類的簡單使用:

String url = "網絡請求的位址";
        HashMap<String, String> params = new HashMap<>();
        // 添加請求參數
        params.put("key", "value");
        // ...
        NetRequest.getFormRequest(url, params, new NetRequest.DataCallBack() {
            @Override
            public void requestSuccess(String result) throws Exception {
                // 請求成功的回調
            }

            @Override
            public void requestFailure(Request request, IOException e) {
                // 請求失敗的回調
            }
        });
           

  至于同步get、post請求同理,而且個人感覺使用較少,便沒有寫出,檔案下載下傳和上傳同理。以上便是我對OKHttp的使用和認識,當然OKHttp遠遠不止這些,以後再慢慢補充。以上均為個人觀點,如有錯誤,歡迎留言指出,以便及時修正。

OKHttp的基本使用和簡單封裝