趁周末时间撸了两天代码,将OkHttp网络请求框架进行了一次简单封装,对于实际开发非常有用。。
此次封装主要针对我们经常使用的网络请求的步骤进行封装,在已有框架OkHttp的基础上进行实际开发的封装
发送一个网络请求,有以下三个功能模块:
一:request处理
二:OkHttp核心处理
三:callback处理
我们进行网络请求组件的封装也是根据这三大模块进行封装的,下面规划一下这次封装的一个思维导图:
根据以上思维导图,我们第一步,先进行request的封装:
以下是封装的一个CommonRequest类:
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核心进行了解耦,对于实际项目的开发以及维护都相当有作用。
到此,网络请求组件的封装已经初步完成,对于一些第三方框架的封装有了一些感悟,感谢慕课网的老师的讲解,也感谢不断学习的自己。
项目源码:源码地址