• Android实际开发之网络请求组件的封装(OkHttp为核心)


    趁周末时间撸了两天代码,将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;
        }
    
    }
    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核心进行了解耦,对于实际项目的开发以及维护都相当有作用。

    到此,网络请求组件的封装已经初步完成,对于一些第三方框架的封装有了一些感悟,感谢慕课网的老师的讲解,也感谢不断学习的自己。

    项目源码:源码地址

  • 相关阅读:
    iOS tableViewCell自适应高度 第三发类库
    iOS 用 SDWebImage 清理图片缓存
    iOS JsonModel 的使用
    Objective-C语法之KVO使用
    iOS开发之 用第三方类库实现轮播图
    OS开发UI篇—使用UItableview完成一个简单的QQ好友列表
    iOS tableView 静态单元格的实现
    iOS沙盒目录结构解析
    ios开发UI篇—使用纯代码自定义UItableviewcell实现一个简单的微博界面布局
    AFNetworking 3.0.4 的使用
  • 原文地址:https://www.cnblogs.com/ouyangduoduo/p/6624466.html
Copyright © 2020-2023  润新知