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

Posted 欧阳生朵

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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核心进行了解耦,对于实际项目的开发以及维护都相当有作用。

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

项目源码:源码地址

以上是关于Android实际开发之网络请求组件的封装(OkHttp为核心)的主要内容,如果未能解决你的问题,请参考以下文章

Android开发之MVVM模式实践:协程与网络请求的结合

Android之封装好的异步网络请求框架

Xamarin.Android之封装个简单的网络请求类

Xamarin.Android之封装个简单的网络请求类

Android 网络请求框架之Retrofit 的 详细使用

Android 网络请求框架之Retrofit 的 详细使用