趁週末時間擼了兩天代碼,將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; } }
以上,咱們的就把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核心進行了解耦,對於實際項目的開發以及維護都至關有做用。
到此,網絡請求組件的封裝已經初步完成,對於一些第三方框架的封裝有了一些感悟,感謝慕課網的老師的講解,也感謝不斷學習的本身。
項目源碼:源碼地址