Android實際開發之網絡請求組件的封裝(OkHttp爲核心)

趁週末時間擼了兩天代碼,將OkHttp網絡請求框架進行了一次簡單封裝,對於實際開發很是有用。。java

 

這次封裝主要針對咱們常常使用的網絡請求的步驟進行封裝,在已有框架OkHttp的基礎上進行實際開發的封裝android

發送一個網絡請求,有如下三個功能模塊:git

一:request處理github

二:OkHttp核心處理json

三:callback處理服務器

咱們進行網絡請求組件的封裝也是根據這三大模塊進行封裝的,下面規劃一下此次封裝的一個思惟導圖:網絡

 

根據以上思惟導圖,咱們第一步,先進行request的封裝:session

如下是封裝的一個CommonRequest類:app

 1 package com.oysd.okhttp.request;
 2 
 3 import java.util.Map;
 4 
 5 import okhttp3.FormBody;
 6 import okhttp3.Request;
 7 
 8 /**
 9  * *****************************************************************
10  * * 文件做者:ouyangshengduo
11  * * 建立時間:2017/3/25
12  * * 文件描述:接收請求參數,爲咱們生成request對象
13  * * 修改歷史:2017/3/25 21:02*************************************
14  **/
15 
16 public class CommonRequest {
17 
18     /**
19      *
20      * @param url
21      * @param params
22      * @return返回一個建立好的Request對象
23      */
24     public static Request createPostRequest(String url, RequestParams params){
25 
26         FormBody.Builder mFormBodyBuild = new FormBody.Builder();
27 
28         if(params != null){
29             for(Map.Entry<String,String> entry: params.urlParams.entrySet()){
30                 //將請求參數遍歷添加到咱們的請求構件類中
31                 mFormBodyBuild.add(entry.getKey(),entry.getValue());
32             }
33         }
34         //經過請求構件類的build方法獲取到真正的請求體對象
35         FormBody mFormBody = mFormBodyBuild.build();
36         return new Request.Builder().url(url).post(mFormBody).build();
37     }
38 
39     /**
40      *
41      * @param url
42      * @param params
43      * @return 經過傳入的參數,返回一個建立Get類型的Request對象
44      */
45     public static Request createGetRequest(String url,RequestParams params){
46 
47         StringBuilder urlBuilder = new StringBuilder(url).append("?");
48         if(params != null){
49             for(Map.Entry<String,String> entry: params.urlParams.entrySet()){
50                 //將請求參數遍歷添加到咱們的請求構件類中
51                 urlBuilder.append(entry.getKey()).append("=").
52                         append(entry.getValue()).append("&");
53             }
54         }
55 
56         return new Request.Builder().url(urlBuilder.substring(0,urlBuilder.length() - 1))
57                 .get().build();
58     }
59 
60 }

 

其中的RequestParams功能比較簡單,是封裝全部的請求參數到HashMap中,可展開查看代碼內容:框架

package com.oysd.okhttp.request;

import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * *****************************************************************
 * * 文件做者:ouyangshengduo
 * * 建立時間:2017/3/25
 * * 文件描述:封裝全部的請求參數到HashMap中
 * * 修改歷史:2017/3/25 16:36*************************************
 **/

public class RequestParams {

    public ConcurrentHashMap<String,String> urlParams = new ConcurrentHashMap<String,String>();
    public ConcurrentHashMap<String,Object> fileParams = new ConcurrentHashMap<String,Object>();

    /**
     * Constructs a new empty {@code RequestParams} instance.
     */
    public RequestParams() {
        this((Map<String, String>) null);
    }

    /**
     * Constructs a new RequestParams instance containing the key/value string
     * params from the specified map.
     *
     * @param source the source key/value string map to add.
     */
    public RequestParams(Map<String, String> source) {
        if (source != null) {
            for (Map.Entry<String, String> entry : source.entrySet()) {
                put(entry.getKey(), entry.getValue());
            }
        }
    }

    /**
     * Constructs a new RequestParams instance and populate it with a single
     * initial key/value string param.
     *
     * @param key   the key name for the intial param.
     * @param value the value string for the initial param.
     */
    public RequestParams(final String key, final String value) {
        this(new HashMap<String, String>() {
            {
                put(key, value);
            }
        });
    }

    /**
     * Adds a key/value string pair to the request.
     *
     * @param key   the key name for the new param.
     * @param value the value string for the new param.
     */
    public void put(String key, String value) {
        if (key != null && value != null) {
            urlParams.put(key, value);
        }
    }

    public void put(String key, Object object) throws FileNotFoundException {

        if (key != null) {
            fileParams.put(key, object);
        }
    }

    public boolean hasParams() {
        if(urlParams.size() > 0 || fileParams.size() > 0){

            return true;
        }
        return false;
    }

}
View Code

 

以上,咱們的就把request的功能處理封裝好了,其中包含的模塊有請求參數的封裝,url的傳入,建立好get/post的請求對象(正如思惟導圖上所展現的request的處理)

 

第二步,對OkHttp核心進行封裝,下面咱們新建類CommonOkHttpClient,並實現OkHttp核心的發送get/post請求,請求相關參數的設置,以及https的支持:

 1 package com.oysd.okhttp;
 2 
 3 import com.oysd.okhttp.https.HttpsUtils;
 4 import com.oysd.okhttp.response.CommonJsonCallback;
 5 
 6 import java.util.concurrent.TimeUnit;
 7 
 8 import javax.net.ssl.HostnameVerifier;
 9 import javax.net.ssl.SSLSession;
10 
11 import okhttp3.Call;
12 import okhttp3.OkHttpClient;
13 import okhttp3.Request;
14 
15 /**
16  * *****************************************************************
17  * * 文件做者:ouyangshengduo
18  * * 建立時間:2017/3/25
19  * * 文件描述:請求的發送,請求參數的配置,https的支持
20  * * 修改歷史:2017/3/25 21:21*************************************
21  **/
22 
23 public class CommonOkHttpClient {
24 
25     private static final int TIME_OUT = 30;//超時參數
26     private static OkHttpClient mOkHttpClient;
27 
28     //爲咱們的client去配置參數
29     static{
30 
31         //建立咱們client對象的構建者
32         OkHttpClient.Builder okHttpBuilder = new OkHttpClient().newBuilder();
33         //爲構建者填充超時時間
34         okHttpBuilder.connectTimeout(TIME_OUT, TimeUnit.SECONDS);
35         okHttpBuilder.readTimeout(TIME_OUT,TimeUnit.SECONDS);
36         okHttpBuilder.writeTimeout(TIME_OUT,TimeUnit.SECONDS);
37 
38         //確保支持重定向
39         okHttpBuilder.followRedirects(true);
40 
41         //https支持
42         okHttpBuilder.hostnameVerifier(new HostnameVerifier() {
43             @Override
44             public boolean verify(String hostname, SSLSession session) {
45                 return true;
46             }
47         });
48         okHttpBuilder.sslSocketFactory(HttpsUtils.getSslSocketFactory());
49         //生成咱們client對象
50         mOkHttpClient = okHttpBuilder.build();
51     }
52 
53 
54     /**
55      *
56      * @param request
57      * @param commonCallback
58      * @return返回Call實例
59      */
60     public static Call sendRequest(Request request, CommonJsonCallback commonCallback){
61 
62         Call call = mOkHttpClient.newCall(request);
63         call.enqueue(commonCallback);
64         return call;
65     }
66 
67 
68 }

以上就是把OkHttp核心的一些請求參數進行設置,根據咱們實際開發的環境進行一些靜態參數設置,

在這裏說明一下,對於一些公用的一些組件,正確使用static並不會形成內存泄露,要知道Android源碼裏面,不少都用到了static,因此能夠放心。。

 

第三步,就是對於咱們OkHttp核心的回調進行封裝了

新建類DisposeDataListener做爲咱們的自定義事件監聽,和OkHttp的onSucess和onFailure相似,但這個事件監聽是屬於咱們項目本身的,

萬一哪天OkHttp的開發團隊將這兩個事件更名字了或者不用了,咱們本身的項目中的業務層至少不會產生任何影響

 1 package com.oysd.okhttp.listener;
 2 
 3 /**
 4  * *****************************************************************
 5  * * 文件做者:ouyangshengduo
 6  * * 建立時間:2017/3/26
 7  * * 文件描述:自定義事件監聽
 8  * * 修改歷史:2017/3/26 10:22*************************************
 9  **/
10 
11 public interface DisposeDataListener {
12 
13     /**
14      * 請求成功回調事件處理
15      * @param responseObj
16      */
17     public void onSuccess(Object responseObj);
18 
19     /**
20      * 請求失敗回調事件處理
21      * @param responseObj
22      */
23     public void onFailure(Object responseObj);
24 }

而後新建一個DisposeDataHandle類,做爲咱們實際開發中用的最多的json數據的一個json對象到實體對象的一個轉化

 1 package com.oysd.okhttp.listener;
 2 
 3 /**
 4  * *****************************************************************
 5  * * 文件做者:ouyangshengduo
 6  * * 建立時間:2017/3/26
 7  * * 文件描述:json對象到實體對象的一個講話
 8  * * 修改歷史:2017/3/26 10:42*************************************
 9  **/
10 
11 public class DisposeDataHandle {
12 
13     public DisposeDataListener mListener;
14     public Class<?> mClass = null;//字節碼
15 
16     /**
17      * 數據原封不動
18      * @param listener
19      */
20     public DisposeDataHandle(DisposeDataListener listener){
21         this.mListener = listener;
22     }
23 
24     /**
25      * json對象到實體對象的轉化
26      * @param listener
27      * @param clazz
28      */
29     public DisposeDataHandle(DisposeDataListener listener,Class<?> clazz){
30         this.mListener = listener;
31         this.mClass = clazz;
32     }
33 }

 

以上是做爲回調內容一些處理功能,對於response的封裝,主要功能在CommonJsonCallback(以實際開發中遇到最多的json格式的處理爲例):

  1 package com.oysd.okhttp.response;
  2 
  3 import android.os.Handler;
  4 import android.os.Looper;
  5 
  6 import com.google.gson.Gson;
  7 import com.oysd.okhttp.exception.OkHttpException;
  8 import com.oysd.okhttp.listener.DisposeDataHandle;
  9 import com.oysd.okhttp.listener.DisposeDataListener;
 10 
 11 import org.json.JSONObject;
 12 
 13 import java.io.IOException;
 14 
 15 import okhttp3.Call;
 16 import okhttp3.Callback;
 17 import okhttp3.Response;
 18 
 19 /**
 20  * *****************************************************************
 21  * * 文件做者:ouyangshengduo
 22  * * 建立時間:2017/3/26
 23  * * 文件描述:專門處理JSON的回調響應
 24  * * 修改歷史:2017/3/26 10:53*************************************
 25  **/
 26 
 27 public class CommonJsonCallback implements Callback{
 28 
 29     //與服務器返回的字段的一個對應關係
 30     protected  final String RESULT_CODE = "ecode";//有返回則對於http請求來講是成功的
 31     protected  final int RESULT_CODE_VALUE = 0;
 32     protected  final String ERROR_MSG = "emsg";
 33     protected  final String EMPTY_MSG = "";
 34 
 35     /**
 36      * 自定義了一些咱們常見的一些異常類型
 37      */
 38     protected final int NETWORK_ERROR = -1;//網絡錯誤
 39     protected final int JSON_ERROR = -2;//json解析錯誤
 40     protected final int OTHER_ERROR = -3;//其餘錯誤
 41 
 42     private Class<?> mClass;
 43     private Handler mDeliveryHandler;//進行消息的轉發,將子線程的數據轉發到UI線程
 44     private DisposeDataListener mListener;
 45 
 46     public CommonJsonCallback(DisposeDataHandle handle){
 47         this.mClass = handle.mClass;
 48         this.mListener = handle.mListener;
 49         this.mDeliveryHandler = new Handler(Looper.getMainLooper());
 50     }
 51 
 52     //請求失敗處理
 53     @Override
 54     public void onFailure(final Call call,final IOException e) {
 55 
 56         mDeliveryHandler.post(new Runnable() {
 57             @Override
 58             public void run() {
 59 
 60                 mListener.onFailure(new OkHttpException(NETWORK_ERROR,e));
 61             }
 62         });
 63     }
 64 
 65     @Override
 66     public void onResponse(Call call, Response response) throws IOException {
 67 
 68         final String result = response.body().toString();
 69         mDeliveryHandler.post(new Runnable() {
 70             @Override
 71             public void run() {
 72                 handleResponse(result);
 73             }
 74         });
 75     }
 76 
 77     /**
 78      * 處理服務器返回的數據
 79      * @param responseObj
 80      */
 81     private void handleResponse(Object responseObj){
 82 
 83         //爲了保證代碼的健壯性
 84         if(responseObj == null && responseObj.toString().trim().equals("")){
 85 
 86             mListener.onFailure(new OkHttpException(NETWORK_ERROR,EMPTY_MSG));
 87             return;
 88         }
 89 
 90         try{
 91             JSONObject result = new JSONObject(responseObj.toString());
 92             //開始嘗試解析json
 93             if(result.has(RESULT_CODE)){
 94 
 95                 //從json對象中取出咱們的響應碼,若爲0(與服務器一致),則是正常的響應
 96                 if(result.getInt(RESULT_CODE) == RESULT_CODE_VALUE){
 97 
 98                     if(mClass == null){
 99                         mListener.onSuccess(responseObj);
100                     }else{
101                         //即,須要咱們將json對象轉化爲實體對象
102                         Gson gson = new Gson();
103                         Object obj = gson.fromJson(responseObj.toString(),mClass);
104                         //標明正確的轉化爲了實體對象
105                         if(obj != null){
106                             mListener.onSuccess(obj);
107                         }else{
108                             //返回的不是合法的json
109                             mListener.onFailure(new OkHttpException(JSON_ERROR,EMPTY_MSG));
110                         }
111                     }
112                 }else{
113                     //將服務器返回給咱們的異常回調到應用層去處理
114                     mListener.onFailure(new OkHttpException(OTHER_ERROR,result.get(RESULT_CODE)));
115                 }
116             }
117 
118         }catch(Exception e){
119             mListener.onFailure(new OkHttpException(OTHER_ERROR,e.getMessage()));
120         }
121 
122     }
123 }

 

以上就是對於response的一個封裝,其中包含的有回調數據的處理,異常處理,將網絡請求結果等信息轉發到UI線程,以及實際開發中遇到不少的json轉化對應的實體

根據思惟導圖裏面的描述,已經將request層,OkHttp核心層,response層都進行了封裝,對於實際開發中用到的網絡請求,咱們已經造成了本身的網絡請求組件,對於

咱們項目的業務層與OkHttp核心進行了解耦,對於實際項目的開發以及維護都至關有做用。

到此,網絡請求組件的封裝已經初步完成,對於一些第三方框架的封裝有了一些感悟,感謝慕課網的老師的講解,也感謝不斷學習的本身。

項目源碼:源碼地址

相關文章
相關標籤/搜索