Android之利用volley搭建简洁网络框架

Android之利用volley搭建简洁网络框架

文章链接:

知识点:

  1. 为什么一定要联网操作;
  2. 利用volley搭建合适自己的简介网络请求框架;
  3. 新名词记录{枚举;手动解析json}

概述

在当今互联网大潮中,中国的网络已经很普及了,互联网已经不是一个新鲜的词语。我们也是搭上了互联网快车,而且是移动互联网这一节车厢。
如今,在进行APP开发中,使用网络请求数据已经是每个APP必备的内容了。我敢说是一定有的,因为你不需要为用户提供账号系统和存储等,至少都要“收集用户信息”,你的APP被每一位用户握在手里,这是最快捷触达用户的途径了。

“用户为中心”一直是我们公司的的口号之一。那么要了解用户,就需要获取用户的各种信息,才能够更加好的“运营用户”。

所以,这里是总结:每一个APP都需要进行联网。

如果没有联网操作的APP,那就是在耍流氓了。没有谁会丢这么一个APP到用户手里吧?!

完。。。。。。


打造联网框架

俗话说:我们要站在巨人的肩膀上。联网的巨人之一就是volley。如果大家对volley还不熟悉,可以去百度,里面大把的教程。我这里对其进行封装,打造自己的简单易用的网络框架。

我已经将代码注释的很清楚了。各位看官慢慢品尝。

第一步:实体基类 AbsBaseBean.java
package com.yaojt.sdk.java;

import com.yaojt.sdk.java.utils.CommonLog;

import org.json.JSONObject;

import java.io.Serializable;

/**
 * desc:基类basebean
 * <p>
 * author:kuyu.yaojt (tanksu)
 * <p>
 * email:yaojt@kuyumall.com
 * <p>
 * blog:http://blog.youkuaiyun.com/qq_16628781
 * <p>
 * date:17/4/9
 */

public abstract class AbsBaseBean implements Serializable {
    private String TAG = AbsBaseBean.class.getSimpleName();
    /**
     * 请求成功码
     */
    public final String SUCCESS_CODE = "0";
    /**
     * 系统错误,返回码
     */
    public final String SYSTEM_ERROR_CODE = "-1";
    /**
     * 密码错误返回码
     */
    public final String INVALID_PARAMS_CODE = "1";

    /**
     * token不可用返回码
     */
    private final String EMPTY_TOKEN_CODE = "-3";
    /**
     * 需要重新登录的返回码
     */
    private final String LOGOUT_CODE = "-4";

    private String code;
    private String message;
    private String sign;

    private String decodeData;
    private String originalData;

    ResponseStatus mResponseStatus;

    /**
     * 解析返回的数据
     *
     * @param response 返回的数据
     */
    public void parseResponse(String response) {
        if (response == null || response.equals("")) {
            mResponseStatus = ResponseStatus.RESPONSE_EXCEPTION;
            return;
        }
        try {

            JSONObject jsonObject = new JSONObject(response);
            code = jsonObject.optString("code");
            message = jsonObject.optString("message");
            mResponseStatus = SUCCESS_CODE.equals(code) ?
                    ResponseStatus.SUCCESS :
                    (SYSTEM_ERROR_CODE.equals(code) ?
                            ResponseStatus.SERVICE_EXCEPTION : ResponseStatus.PARAMS_EXCEPTION);
            //检查是否被挤下线
            if (LOGOUT_CODE.equals(code) || EMPTY_TOKEN_CODE.equals(code)) {
                mResponseStatus = ResponseStatus.LOGOUT;
                //下线处理后续操作
            }
            originalData = jsonObject.optString("data");
            if (null == originalData || "null".equals(originalData) || "".equals(originalData)) {
                mResponseStatus = ResponseStatus.PARAMS_EXCEPTION;
                //toast提示
                return;
            }
            //如果有传输加密,对数据进行解密
            //decodeData = EncryptUtil.doubleDecrypt(originalData);
            decodeData = originalData;
            CommonLog.logInfo("decodeData", decodeData);
            if ("[]".equals(decodeData) || "{}".equals(decodeData)) {
                mResponseStatus = ResponseStatus.PARAMS_EXCEPTION;
                //ToastUtils.makeText(MyApplication.getInstance(), message, ToastUtils.ONE_SECOND);
                return;
            }
            //手动解析数据
            parseData(originalData, decodeData);
        } catch (Exception e) {
            mResponseStatus = ResponseStatus.OTHER_ERROR;
            e.printStackTrace();
        }
    }

    /**
     * data数据体
     *
     * @param orign  原始数据
     * @param decode 解密数据
     */
    public abstract void parseData(String orign, String decode);

    /**
     * 从JSON中取key对应的值,无值是返回默认值
     *
     * @param object       JSONObject
     * @param key          值对应的key
     * @param defaultValue 默认值
     * @return value 如果有对应的key,则返回对应的值,反之返回defaultValue
     */
    protected String getStringFromJsonObject(JSONObject object, String key, String defaultValue) {
        if (null == object || null == key) return defaultValue;
        return object.has(key) ? object.optString(key) : defaultValue;
    }

    /**
     * 返回结果状态
     */
    public enum ResponseStatus {
        /**
         * 成功
         */
        SUCCESS,
        /**
         * 返回数据异常
         */
        RESPONSE_EXCEPTION,
        /**
         * 网络连接失败
         */
        NETWORK_ERROR,
        /**
         * 服务异常
         */
        SERVICE_EXCEPTION,
        /**
         * 参数异常
         */
        PARAMS_EXCEPTION,
        /**
         * 其他 错误
         */
        OTHER_ERROR,
        /**
         * 登录过期
         */
        LOGOUT
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public String getSign() {
        return sign;
    }

    public void setSign(String sign) {
        this.sign = sign;
    }

    public String getDecodeData() {
        return decodeData;
    }

    public void setDecodeData(String decodeData) {
        this.decodeData = decodeData;
    }

    public String getOriginalData() {
        return originalData;
    }

    public void setOriginalData(String originalData) {
        this.originalData = originalData;
    }

    public ResponseStatus getmResponseStatus() {
        return mResponseStatus;
    }

    public void setmResponseStatus(ResponseStatus mResponseStatus) {
        this.mResponseStatus = mResponseStatus;
    }
}

上面的代码主要有几点:
1. 你需要一个volley.jar的包;
2. 定义一系列的请求返回码(需要和后台商定);
3. 定义一个请求异常枚举(ResponseStatus);
4. parseResponse(String response)方法对原始的数据进行处理:如果没有加密,直接从json中获取到数据;如果有加密,需要进行解密之后才进行操作;最后调用parseData()方法进行手动解析数据,所以要求所有的实体类都要继承此基本实体类;此类只是对共有的几个属性值和结果进行判断,将具体的操作给到子类进行处理;
5. 一些基本的setter,getter方法;


第二步:进行网络封装

在这里,实现默认已经加入volley的代码。
因为我们就是使用volley进行网络请求处理的。

我们这里主要是利用volley进行< JSONObject>请求,因为绝大多数的网络传输都是使用json。我们这里也不例外,不过项目里面对数据进行了aes+des双重加密。

具体代码如下所示:JsonRequestImpl.java

package com.yaojt.sdk.java.network;

import com.android.volley.AuthFailureError;
import com.android.volley.NetworkResponse;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.toolbox.HttpHeaderParser;
import com.yaojt.sdk.java.utils.CommonLog;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

/**
 * desc:自定义请求,利用map传參
 * <p>
 * author:kuyu.yaojt (tanksu)
 * <p>
 * email:yaojt@kuyumall.com
 * <p>
 * blog:http://blog.youkuaiyun.com/qq_16628781
 * <p>
 * date:17/4/9
 */

public class JsonRequestImpl extends Request<JSONObject> {
    private Map<String, String> mMap;
    private Response.Listener<JSONObject> mListener;
    //private AppSharedPreferences appSharedPreferences;

    /**
     * 构造方法
     *
     * @param url           请求地址
     * @param listener      成功监听器
     * @param errorListener 错误监听器
     * @param map           入参数据
     */
    public JsonRequestImpl(int method, String url, Response.Listener<JSONObject> listener,
                           Response.ErrorListener errorListener, Map<String, String> map) {
        super(Request.Method.POST, url, errorListener);
        mListener = listener;
        mMap = map;
        this.method = method;
    }

    private int method;

    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        return addHeaders(method == 1 ? "POST" : (method == 2 ? "PUT" : "GET") + "-Header");
    }

    /**
     * <li>请求header</li>
     *
     * @param tag 日志标记请求类型
     * @return headers
     */
    protected Map<String, String> addHeaders(String tag) {
        Map<String, String> header = new HashMap<>();
        //String accessToken = new AppSharedPreferences(MyApplication.getInstance()).getAccessToken();
        String accessToken = "123456789";
        String str = null;
        try {
            String byteStr = new String(accessToken.getBytes(), "utf-8");
            str = URLEncoder.encode(byteStr, "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        header.put("login-token", str); //带入token
        CommonLog.logInfo(tag, header.toString());
        return header;
    }

    @Override
    protected Response<JSONObject> parseNetworkResponse(NetworkResponse networkResponse) {
        try {
            String jsonStr = new String(networkResponse.data, HttpHeaderParser.parseCharset(networkResponse.headers));
            return Response.success(new JSONObject(jsonStr), HttpHeaderParser.parseCacheHeaders(networkResponse));
        } catch (UnsupportedEncodingException | JSONException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void deliverResponse(JSONObject jsonObject) {
        if (null != mListener) mListener.onResponse(jsonObject);
    }

    //mMap是已经按照前面的方式,设置了参数的实例
    @Override
    protected Map<String, String> getParams() throws AuthFailureError {
        return mMap;
    }

}

说明:
1. 传入必要的参数URL,入参,成功监听和失败监听;
2. 请求的头部加入信息,例如token等等;


第三步:便捷使用

下面这个使用类就比较简单了。

package com.yaojt.sdk.java.network;

import android.content.Context;

import com.android.volley.toolbox.Volley;
import com.yaojt.sdk.java.AbsBaseBean;
import com.yaojt.sdk.java.i.RequestCallBack;

import java.util.Map;

/**
 * desc:sdk中的网络请求处理类
 * 注意:这里有一个问题,当用户传入的是activity的context,会造成内存泄漏
 * 所以建议将此类卸载可以引用application的module下面
 * <p>
 * author:kuyu.yaojt (tanksu)
 * <p>
 * email:yaojt@kuyumall.com
 * <p>
 * blog:http://blog.youkuaiyun.com/qq_16628781
 * <p>
 * date:17/4/9
 */

public class HttpRequestHandler extends AbsHttpRequest {

    protected static final String DEVICE = "Android";
    protected static final String VERSION = "1.0";

    private static HttpRequestHandler sVolleyHandler;

    /**
     * 构造函数私有化
     */
    private HttpRequestHandler(Context context) {
        super();
        mRequestQueue = Volley.newRequestQueue(context);
    }

    /**
     * 网络请求单例模式
     *
     * @return VolleyHandler
     */
    public static HttpRequestHandler getInstance(Context context) {
        if (sVolleyHandler == null) {
            synchronized (HttpRequestHandler.class) {
                if (sVolleyHandler == null) {
                    sVolleyHandler = new HttpRequestHandler(context);
                }
            }
        }
        return sVolleyHandler;
    }

    /**
     * post json请求
     *
     * @param url       请求链接地址
     * @param params    post请求参数
     * @param baseModel BaseModel
     * @param callBack  TaskCallBack
     */
    public void postJsonRequest(Context context, String url, final Map<String, String> params,
                                final AbsBaseBean baseModel, final RequestCallBack callBack) {
        super.postJsonRequest(context, url, params, baseModel, callBack);
    }

    @Override
    protected boolean checkNetworkVisiable() {
        //网络检查操作
        return true;
    }

}

说明:
1. 使用单例并加锁的方式保证单例唯一性和安全性;
2. 提供一个post方式的网络请求方法给外部调用;
3. 网络检查部分代码没有实现,需要自己去实现;

注意:这里有一个问题,当用户传入的是activity的context,会造成内存泄漏所以建议将此类卸载可以引用application的module下面。我这里使用的是sdk的一个module,不能够直接应用application的实现类。

总结

上面的使用方式很简介,对于网络请求的底层,例如线程、线程池等等,volley都做了比较好的封装,我们只管上层的调用开发,不用关注细节。

当然,也有不好的,我们毕竟还是需要知道线程的创建和使用等等的知识。这一块是进阶的必备功课。接下来我也会新开一篇文章,讲解利用最原始的方式进行网络请求框架的搭建和使用。

以上就是所有内容,如有任何问题,请及时与我联系,谢谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值