volley 二次封装,项目实际应用

2018-04-16  本文已影响0人  木小伍

前言

volley 出来也这么久了,在这期间,也陆陆续续的出了各种各样的网络请求框架,每一个的框架都说自己是世界上最好的框架,然后拿出其他的框架的劣势来做对比。我个人还是觉得,最好的框架是自己会用的框架,能够满足工作需要的框架就是好框架。

封装思路

1.建立全局的网络请求工具类
2.自定义请求(现在项目大部分都是post请求,所以目前只自定义了json的post请求,string的post请求)
3.请求的发送,与返回统一封装,一步到位

结构分析(最底部有完整的项目链接)

整个demo的结构图如下


结构图.png

RequestListener:响应监听接口,负责 response返回后针对业务对象的逻辑处理,主要声明了onSuccess(),onError(),两个方法,如果项目有其他需要可以进行其他操作

public interface RequestListener {

    void onSuccess(String result);

    void onError(String printMe);
}

AbsRequestListener:对RequestListener的再次封装,主要实现的是对onError()方法的统一处理,在使用的时候就不必重写onError()方法了。

public abstract class AbsRequestListener implements RequestListener {
    @NonNull
    protected Context mContext;
    public AbsRequestListener(Context context) {
        this.mContext = context;
    }
    @Override
    public void onError(String printMe) {
        if (null != mContext)
            Toast.makeText(mContext,printMe,Toast.LENGTH_SHORT).show();
    }
}

IMErrorListener:错误的回调,对response的onError()方法的重写,错误可能是服务器错误,也可能是volley内部错误,主要方法如下:

 /**
     * 接口返回错误信息,进行相应的操作
     *
     * @param error
     */
    @Override
    public void onErrorResponse(VolleyError error) {

        //操作演示
        requestListener.onError(error.getMessage());
//        LoadingDialog.dismiss();
//
//        Resources resources = App.getInstance().getResources();
//       //错误的类型
//        this.requestListener.onError(error instanceof TimeoutError ? resources.getString(R.string.net_error_timeout) :
//                (error instanceof NoConnectionError ? resources.getString(R.string.net_error_noConnection) : resources.getString(R.string.net_error_ununited)));
//
//        if (AppConfig.DEBUG && error != null && error.networkResponse != null && error.networkResponse.data != null) {
//            byte[] htmlBodyBytes = error.networkResponse.data;
//            if (htmlBodyBytes != null) {
//                CommonUtils.LOG_D(getClass(), "VolleyError=" + new String(htmlBodyBytes));
//            }
//        }
    }

IMJsonListener:(post json方式)成功返回的响应监听类,对成功返回的数据进行二次处理。

    @Override
    public void onResponse(JSONObject response) {
        try {
            //     LoadingDialog.dismiss();
            // 将JSONObject转换成String
            String responseText = response.toString();
            // 获得请求结果
            Resources res = mContext.getResources();
            // 返回对象为NULL、空、以及状态码为-1时
            if (TextUtils.isEmpty(responseText)) {
                this.requestListener.onError("服务器貌似GG了...");
                return;
            }
            // 获取状态码
            ResponseInfo responseInfo = JsonUtils.json2Object(responseText, ResponseInfo.class);
            // response不符合规范
            if (null == responseInfo) {
                this.requestListener.onError("服务器还是GG了");
                return;
            }
            if (200 == responseInfo.getCode()) { //服务器正常,回调到onsucess方法
                this.requestListener.onSuccess(JsonUtils.getJSONObjectKeyVal(responseText,"data"));
            }
//
        } catch (Exception e) {
//            if (BuildConfig.DEBUG) {//调试模式下直接抛出异常
//                throw e;
//            } else {//release环境下提示错误,同时上报异常
//                this.requestListener.onError(mContext.getResources().getString(R.string.net_error_ununited));
//                MobclickAgent.reportError(mContext, e);
//            }
        }
    }

IMStringListener:(post String方式)成功返回的响应监听类,对成功返回的数据进行二次处理。主要代码同上。

PostJsonRequset:自定义的json 请求。主要重写了getHeaders()方法。
PostStringRequest:自定义的String请求,主要重写了getHeaders()方法和getParams()方法
HttpUtil:网络请求的工具类,对volley的封装,请求方式的声明。
BeanInfo:javaBean 的实体类,接口返回的数据实体类
ResponseInfo:基本的返回数据的实体类,基本格式如下:

{
    "code": 200,
    "msg": "成功!",
    "data": [....]
}

JsonUtils:Gson的工具类,主要用于Javabean 和 json数据的互转。

封装第一步

创建HttpUtils,这个类主要声明并实例化了RequestQueue,采用单例模式对外暴露一个静态的方法以获取实例对象,以及规定了方法的实现。
实例化RequstQueue,创建单利模式的主要代码如下:

   /**
     * 请求队列
     */
    private RequestQueue queue;
    /**
     * 上下文对象
     */
    private Context mContext;

    /**
     * 会话识别号
     */
    public static String sessionId = "0000";

    private static HttpUtil httpUtil;

    /**
     * 构造函数
     *
     * @param context 上下文对象
     */
    private HttpUtil(Context context) {
        queue = Volley.newRequestQueue(context);
        this.mContext = context;
    }

    public static HttpUtil getInstance(Context context) {
        if (null == httpUtil) {
            httpUtil = new HttpUtil(context);
        }
        if (context != httpUtil.mContext) {
            httpUtil.cancelAllRequestQueue();
            httpUtil = new HttpUtil(context);
        }
        return httpUtil;
    }

JsonPost请求的声明,适用于服务器端需要的传递参数是jsonObject的数据类型。
在这里面我们可以添加每个接口必传的参数,如token之类的,添加方法可以参见StringPost方法的声明

   /**
     * postJson请求
     *
     * @param url             服务器地址
     * @param jsonObject      json 对象
     * @param requestListener 请求监听
     * @return
     */
    private Request<JSONObject> doPostByJson(String url, JSONObject jsonObject,
                                             RequestListener requestListener) {

        PostJsonRequset postJsonRequset = new PostJsonRequset(url, jsonObject,
                new IMJsonListener(requestListener, mContext),
                new IMErrorListener(requestListener, mContext));

        Request<JSONObject> request = queue.add(postJsonRequset);

        // 为请求添加context标记
        request.setTag(mContext);
        return request;
    }

StringPost请求的声明,主要适用于服务器端需要的参数是 key - value的形式。
(一般来说,一个项目通常只会用一种请求方法,要么json,要么string,一般不会两种都出现,如果出现了,可以跟服务器端的聊聊人生了,所以二者JsonPost和StringPost选一个就行了)

 /**
     * postString请求
     *
     * @param url             服务器地址
     * @param params          参数
     * @param requestListener 请求监听
     * @return
     */
    public Request<String> doPostByStr(String url, Map<String, String> params,
                                       RequestListener requestListener) {

        //    在每次请求发起之前先进行网络检查
//        if (!checkNetState(mContext)) {
//            Toast.makeText(mContext, R.string.net_error_check, Toast.LENGTH_SHORT)
//                    .show();
//            return null;
//        }

//依照实际需求添加固定参数 如token之类的
//        params.put("appVerison", BuildConfig.VERSION_NAME);
//        String accessToken = Constants.getAccessToken(mContext);
//        if (!TextUtils.isEmpty(accessToken)) {
//            params.put("access_token", accessToken);
//        }

        PostStringRequest postStrRequset = new PostStringRequest(url, params,
                new IMStringListener(requestListener, mContext),
                new IMErrorListener(requestListener, mContext));

        Request<String> request = queue.add(postStrRequset);

        // 为请求添加context标记
        request.setTag(mContext);
        return request;
    }

为了代码的友好,在这里,同样也添加了网络请求的取消方法,可以在BaseActiviy的onStop()或者onDestory()方法中调用

    /**
     * 清除当前activity所有的请求
     */
    public void cancelAllRequestQueue() {
        if (null != queue && null != mContext) {
            queue.cancelAll(mContext);
            queue.start();
            queue = null;
            mContext = null;
            httpUtil = null;
        }
    }

第二步 -- 自定义请求

自定义PostStringRequst,继承自StringRequst,在这里我我们主要要重写的方法也就三个:
1.构造函数
2.重写请求头
2.重写请求参数
代码如下:

/**
 * 作者: 伍跃武
 * 时间: 2018/4/11
 * 描述:psotString 方式请求
 */

public class PostStringRequest extends StringRequest {

    /**
     * 请求超时时间
     */
    public static final int SOCKET_TIMEOUT = 60 * 1000;
    /**
     * 最大重新请求次数
     */
    public static final int MAX_RETRIES = 0;
    /**
     * 重新请求权重
     */
    public static final float BACK_OFF = 1.0f;
    /**
     * 字符编码
     */
    public static final String ENCODEING = "UTF-8";


    //以上代码建议放在全局的常亮类中,作为演示,暂时在这里

    private Map<String, String> mParams = new HashMap<>();

    public PostStringRequest(String url, Map<String, String> params, Response.Listener<String> listener, Response.ErrorListener errorListener) {
        super(Method.POST, url, listener, errorListener);
        this.mParams = params;
        setRetryPolicy(new DefaultRetryPolicy(SOCKET_TIMEOUT, MAX_RETRIES, BACK_OFF));
    }
    /**
     * 重写请求编码
     *
     * @return
     */
    @Override
    protected String getParamsEncoding() {
        return ENCODEING;
    }

    /**
     * 重写请求头
     *
     * @return
     * @throws AuthFailureError
     */
    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        Map<String, String> headers = new HashMap<String, String>();
        headers.put("Charsert", getParamsEncoding());
//        headers.put("Content-Type", "application/json;charset=utf-8");
//        headers.put("Accept-Encoding", "gzip,deflate");
//        headers.put("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3");
        return headers;
    }

   /**
     * 重写获取参数的方法
     * @return
     */
    @Override
    public Map<String, String> getParams() {
        return mParams;
    }
}

同样,postJsontRequest需要继承自JsonObjectRequest,同样需要重写以上几个方法(除了getParams()方法),详细代码如下:


/**
 * 作者: 伍跃武
 * 时间: 2018/4/11
 * 描述:自定义参数为json的post请求
 */

public class PostJsonRequset extends JsonObjectRequest {

    /**
     * 请求超时时间
     */
    public static final int SOCKET_TIMEOUT = 60 * 1000;
    /**
     * 最大重新请求次数
     */
    public static final int MAX_RETRIES = 0;
    /**
     * 重新请求权重
     */
    public static final float BACK_OFF = 1.0f;
    /**
     * 字符编码
     */
    public static final String ENCODEING = "UTF-8";


    //以上代码建议放在全局的常亮类中,作为演示,暂时在这里

    /**
     * 构造函数
     *
     * @param url           请求链接
     * @param jsonRequest   参数转换成为json对象
     * @param listener      请求成功的监听
     * @param errorListener 请求失败的监听
     */
    public PostJsonRequset(String url, JSONObject jsonRequest, Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) {
        super(Method.POST, url, jsonRequest, listener, errorListener);
        //设置重试策略
        setRetryPolicy(new DefaultRetryPolicy(SOCKET_TIMEOUT, MAX_RETRIES, BACK_OFF));
    }

    /**
     * 重写请求编码
     *
     * @return
     */
    @Override
    protected String getParamsEncoding() {
        return ENCODEING;
    }

    /**
     * 重写请求头
     *
     * @return
     * @throws AuthFailureError
     */
    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        Map<String, String> headers = new HashMap<String, String>();
        headers.put("Charsert", getParamsEncoding());
//        headers.put("Content-Type", "application/json;charset=utf-8");
//        headers.put("Accept-Encoding", "gzip,deflate");
//        headers.put("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3");
        return headers;
    }

第三步

以上基本上就把所有的步骤给完成了,接下来就是实际的操作了,volley的好处就是可以直接在ui线程中进行操作请求返回的结果。请求网络的过程volley自动为我们开辟子线程,可以说我们不需要关心,使用方法如下:

    //建议在BaseActiviy类中初始化,并设置为protected,或者在application类中声明
    private HttpUtil httpUtil;

  switch (view.getId()) {

            case R.id.tv_getNetDataByJson: { //通过json请求
//                Map<String, Object> params = new HashMap<>();
//                params.put("city", "CN101010100");
//                params.put("key", "0ae2908783b34579b5af9e8b369aae22");
//                httpUtil.doPostByJson(BASE_URL, params, requestListener);

            }
            break;
            case R.id.tv_getNetDataByString: { //通过string请求
                String location = "北京";
                Map<String, String> params = new HashMap<>();
                params.put("key", key);
                params.put("location", location);
                httpUtil.doPostByStr(BASE_URL, params, strRequestListener); //发送一个StringRequest请求
         }
            break;
}
    /**
     * 网络请求成功回调的监听---string
     */
    private RequestListener strRequestListener = new AbsRequestListener(this) {
        @Override
        public void onSuccess(String result) {
            textViewResult.setText("String 返回的结果==" + result);
        }
    };

 /**
     * 网络请求成功回调的监听---json
     */
    private RequestListener requestListener = new AbsRequestListener(this) {
        @Override
        public void onSuccess(String result) {

            textViewResult.setText("jsonObject返回的结果==" + result);
        }
    };

附上demo的链接地址volley二次封装Demo,项目实际使用

上一篇下一篇

猜你喜欢

热点阅读