Android目前很多同学使用Volley请求网络数据,但是Volley没有对请求过得数据进行缓存,因此需要我们自己手动缓存。 一下就是我的一种思路,仅供参考

具体使用方法为:

HashMap<String,String> params = new HashMap<>();
params.put("id", "1");params.put("user", "mcoy");

new NetWorkHelper(getActivity()).jacksonMethodRequest("method_id", params, new TypeReference<ReturnTemple<FirstCategories>>(){}, handler, msgId);


NetWorkHelper---对Volley的封装,首先调用CacheManager.get(methodName, params);方法获取缓存中的数据,如果数据为null,则继续发送网络请求。
/** * @version V1.0 网络请求帮助类 * @author: mcoy */public final class NetWorkHelper {    private NetWorkManager netWorkUtils;    public NetWorkHelper(Context context){        netWorkUtils = new NetWorkManager(context);    }    public static final String COMMON_ERROR_MSG = "连接超时,请稍后重试";    public static final int COMMON_ERROR_CODE = 2;    /**     * 使用Jackson请求的方法     * @param methodName     * @param params     * @param handler     * @param msgId     */    public  void jacksonMethodRequest(final String methodName,final HashMap<String,String> params,TypeReference javaType, final Handler handler,final int msgId){        ResponseListener listener =   new ResponseListener(){            @Override            public void onResponse(Object response, boolean isCache) {                PrintLog.log(response.toString());                if (isCache){                    CacheManager.put(methodName, params, response);                }                if (handler != null) {                    Message message = handler.obtainMessage();                    message.what = msgId;                    message.obj = response;                    handler.sendMessage(message);                }            }        };        Object respone = CacheManager.get(methodName, params);        if(respone != null){            listener.onResponse(respone,false);            return;        }        HashMap<String,String> allParams =  Config.setSign(true);        allParams.putAll(params);        Response.ErrorListener errorListener = new Response.ErrorListener() {            @Override            public void onErrorResponse(VolleyError error) {                error.printStackTrace();                if (handler != null) {                    Message message = handler.obtainMessage();                    message.what = msgId;                    message.obj = COMMON_ERROR_MSG;                    handler.sendMessage(message);                }            }        };        netWorkUtils.jacksonRequest(getUrl(methodName), allParams,javaType, listener, errorListener);    }    /**     * Url直接请求     * @param url     * @param params     * @param handler     * @param msgId     */    public void urlRequest(String url,HashMap<String,String> params,JsonParser jsonParser,final Handler handler,final int msgId){        request(url, true, params, jsonParser, handler, msgId);    }    /**     * 通过方法请求     * @param methodName 方法名     * @param params 请求参数     * @param jsonParser Json解析器     * @param handler 回调通知     * @param msgId 通知的Id     */    public void methodRequest(String methodName, final HashMap<String,String> params,final JsonParser jsonParser,final Handler handler,final int msgId){        request(getUrl(methodName),true,params,jsonParser,handler,msgId);    }    /**     * 通过方法请求     * @param methodName 方法名     * @param params 请求参数     * @param jsonParser Json解析器     * @param handler 回调通知     * @param msgId 通知的Id     */    public void methodRequest(String methodName, boolean isLogin,final HashMap<String,String> params,final JsonParser jsonParser,final Handler handler,final int msgId){        request(getUrl(methodName),isLogin,params,jsonParser,handler,msgId);    }    private void request(final String url, boolean isLogin,final HashMap<String,String> params,final JsonParser jsonParser,final Handler handler,final int msgId){        final HashMap<String,String> allParams = Config.setSign(isLogin);        allParams.putAll(params);        Response.Listener listener = new Response.Listener<String>() {            @Override            public void onResponse(String response) {                /**                 * 有些请求默认是没有parser传过来的,出参只求String,譬如联合登录等                 * 所以加了一个else if                 */                Object result;                PrintLog.log(response);                if (jsonParser != null ) {                    jsonParser.json2Obj(response);                    jsonParser.temple.description = jsonParser.temple.getResultDescription();                    result = jsonParser.temple;                } else {                    ReturnTemple temple = new ReturnTemple();                    temple.issuccessful = false;                    temple.description = COMMON_ERROR_MSG;                    temple.result = -100;                    result = temple;                }                if (handler != null) {                    Message message = handler.obtainMessage();                    message.what = msgId;                    message.obj = result;                    handler.sendMessage(message);                }            }        };        Response.ErrorListener errorListener = new Response.ErrorListener() {            @Override            public void onErrorResponse(VolleyError error) {                Object result;                if (jsonParser != null) {                    ReturnTemple temple = new ReturnTemple();                    temple.issuccessful = false;                    temple.description = COMMON_ERROR_MSG;                    temple.result = COMMON_ERROR_CODE;                    result = temple;                } else {                    result = COMMON_ERROR_MSG;                }                if (handler != null) {                    Message message = handler.obtainMessage();                    message.what = msgId;                    message.obj = result;                    handler.sendMessage(message);                }            }        };        netWorkUtils.request(url, allParams, listener, errorListener);    }    /**     * 根据访求名拼装请求的Url     * @param methodName     * @return     */    private String getUrl(String methodName){        String url = Config.getUrl();        if (!StringUtil.isNullOrEmpty(methodName)) {            url = url + "?method=" + methodName;        }        return url;    }}


CacheManager---将针对某一method所请求的数据缓存到本地文件当中,主要是将CacheRule写到本地文件当中
/** * @version V1.0 <缓存管理> * @author: mcoy */public final class CacheManager {    /**     * 一个方法对应的多个Key,比如分类都是同一个方法,但是请求会不一样,可能都要缓存     */    private static HashMap<String, ArrayList<String>> methodKeys;    private static final String keyFileName = "keys.pro";    /**     * 读取缓存的Key     */    public static void readCacheKey() {        methodKeys = (HashMap<String, ArrayList<String>>) readObject(keyFileName);        if (methodKeys == null) {            methodKeys = new HashMap<String, ArrayList<String>>();        }    }    /**     * 保存缓存     */    public static void put(String method, HashMap<String, String> params, Object object) {        long expireTime = CacheConfig.getExpireTime(method);        if (expireTime <= 0 || methodKeys == null) {//有效时间小于0,则不需要缓存            return;        }        String key = createKey(method, params);        if (methodKeys.containsKey(method)) {            ArrayList<String> keys = methodKeys.get(method);            keys.add(key);        } else {            ArrayList<String> keys = new ArrayList<>();            keys.add(key);            methodKeys.put(method, keys);        }        writeObject(methodKeys, keyFileName);        String fileName = key + ".pro";        CacheRule cacheRule = new CacheRule(expireTime, object);        LogModel.log(" put " + method + " " + key + "  " + cacheRule);        writeObject(cacheRule, fileName);    }    public static Object get(String method, HashMap<String, String> params) {        long expireTime = CacheConfig.getExpireTime(method);        if (expireTime <= 0 || methodKeys == null || !methodKeys.containsKey(method)) {//有效时间小于0,则不需要缓存            return null;        }        ArrayList<String> keys = methodKeys.get(method);//        String saveKey = keys.get(method);        String key = createKey(method, params);        String fileName = key + ".pro";//        LogModel.log("get"+method+" "+(saveKey.equals(key))+" path:"+fileName);        CacheRule cacheRule = null;        try {            if (keys.contains(key)) {                cacheRule = (CacheRule) readObject(fileName);            }        } catch (Exception e) {            e.printStackTrace();        }        LogModel.log("get :" + method + " " + key + " " + cacheRule);        if (cacheRule != null && cacheRule.isExpire()) {            return cacheRule.getData();        } else {            return null;        }    }    public static void main(String[] args) {        String method = "category.getCategory";        HashMap<String, String> params = new HashMap<>();        params.put("categoryId", "-3");        System.out.println(createKey(method, params));        System.out.println(CacheRule.getCurrentTime());    }    /**     * 生成Key     *     * @param method 请求的方法名     * @param params 私有参数(除公共参数以外的参数)     * @return     */    private static String createKey(String method, HashMap<String, String> params) {        try {            MessageDigest digest = MessageDigest.getInstance("md5");            digest.digest(method.getBytes("UTF-8"));            StringBuilder builder = new StringBuilder(method);            if (params != null && params.size() > 0) {                Iterator<Map.Entry<String, String>> iterator = params.entrySet().iterator();                while (iterator.hasNext()) {                    Map.Entry<String, String> entry = iterator.next();                    builder.append(entry.getKey()).append("=").append(entry.getValue());                }            }            byte[] tempArray = digest.digest(builder.toString().getBytes("UTF-8"));            StringBuffer keys = new StringBuffer();            for (byte b : tempArray) {                // 与运算                int number = b & 0xff;// 加盐                String str = Integer.toHexString(number);                // System.out.println(str);                if (str.length() == 1) {                    keys.append("0");                }                keys.append(str);            }            return keys.toString().toUpperCase();        } catch (Exception e) {            e.printStackTrace();        }        return method.toUpperCase();    }    /**     * 将对象写到文件中     *     * @param object     * @param fileName     */    private static void writeObject(Object object, String fileName) {        try {            ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(new File(CacheConfig.getCachePath() + fileName)));            oo.writeObject(object);            oo.close();        } catch (IOException e) {            e.printStackTrace();        }    }    /**     * 读取对象     *     * @param fileName     * @return     */    private static Object readObject(String fileName) {        Object result = null;        try {            File file = new File(CacheConfig.getCachePath() + fileName);            if (file.exists()) {                ObjectInputStream oi = new ObjectInputStream(new FileInputStream(file));                result = oi.readObject();                oi.close();            }        } catch (Exception e) {            e.printStackTrace();        }        return result;    }}

CacheConfig---初始化哪些方法需要做缓存处理,以及缓存的有效时间
/** * @version V1.0 <设置哪些类数据需要缓存> * @author: mcoy */public final class CacheConfig {    /**方法对应的缓存有效时间,时间是毫秒*/    private static HashMap<String,Long> methodExpireTimes = new HashMap<String, Long>();    private static String cachePath = null;    static {        methodExpireTimes.put(ConstMethod.GET_CATEGORY_LIST,30 * 60 * 1000L);        methodExpireTimes.put(ConstMethod.GET_NEW_CATEGORY_LIST,30 * 60 * 1000L);    }    /**     * 初始化缓存路径     * @param context     */    public static void init(Context context){        cachePath = context.getFilesDir().getPath()+ File.separator+"cache"+File.separator;        File file = new File(cachePath);        if(!file.exists()){            file.mkdirs();        }        CacheManager.readCacheKey();    }    /**缓存路径*/    public static String getCachePath() {        return cachePath;    }    /**     * 获取有方法对应的有效时间,如果方法没有添加缓存或者缓存时间小于0,则不添加缓存     * @param method     * @return     */    public static long getExpireTime(String method){        if(methodExpireTimes.containsKey(method)){            return methodExpireTimes.get(method);        }else {            return -1;        }    }}

CacheRule---主要有两个参数,expireTime需要缓存的时间, data需要缓存的数据
public class CacheRule implements Serializable{    /** 有效时间 */    public long expireTime;    /** 缓存时间*/    public long cacheTime;    /** 缓存数据 */    private Object data;    public CacheRule(long expireTime,Object data){        cacheTime =  getCurrentTime();        this.expireTime = expireTime;        this.data = data;    }    public Object getData() {        return data;    }    public void setData(Object data) {        this.data = data;    }    @Override    public int hashCode() {        return BeanTools.createHashcode(expireTime, cacheTime, data);    }    @Override    public String toString() {        StringBuilder builder = new StringBuilder();        builder.append("expireTime:").append(expireTime).append(" cacheTime:").append(cacheTime)                .append(" curTime:").append(getCurrentTime())                .append(" isExpire:").append(isExpire()).append(" data:").append(data==null?"null":data.toString());        return builder.toString();    }    /**     * 数据是否有效     * @return     */    public boolean isExpire(){        long curTime = getCurrentTime();        return  curTime>(expireTime+cacheTime)?false:true;    }    /**     * 获取当前时间     * @return     */    public static long getCurrentTime(){//        if (Build.VERSION_CODES.JELLY_BEAN_MR1 <= Build.VERSION.SDK_INT) {//            return SystemClock.elapsedRealtimeNanos();//        } else {            return System.currentTimeMillis();//        }    }}


NetWorkManager---往RequestQueue中添加JacksonRequest请求,然后Volley会去请求数据
/** * 网络请求的工具类 */public final class NetWorkManager {    private RequestQueue requestQueue ;    public NetWorkManager(Context context){        requestQueue = Volley.newRequestQueue(context);    }    /**     * 使用Jackson解析请求的方法     * @param url     * @param params     * @param javaType 成功时返回的Java类型     * @param listener     * @param errorListener     */    public void jacksonRequest(final String url,final HashMap<String,String> params,TypeReference javaType, ResponseListener listener, Response.ErrorListener errorListener){        JacksonRequest jacksonRequest = new JacksonRequest(url,javaType,params,listener,errorListener);        requestQueue.add(jacksonRequest);    }    /**     * 普通的网络请求,返回的Json     * @param url     * @param params     * @param listener     * @param errorListener     */    public void request(final String url,final HashMap<String,String> params,Response.Listener listener,Response.ErrorListener errorListener){        StringRequest stringRequest = new StringRequest(Request.Method.POST,url,listener,errorListener){            @Override            protected Map<String, String> getParams() throws AuthFailureError {                if (PrintLog.DEBUG) {                    Iterator<Map.Entry<String,String>> iterator = params.entrySet().iterator();                    StringBuilder builder = new StringBuilder(url+"  ");                    while (iterator.hasNext()){                        Map.Entry<String,String> entry = iterator.next();                        builder.append(entry.getKey()+":"+entry.getValue()).append("; ");                    }                    PrintLog.log(builder.toString());                }                return  params;            }        };        requestQueue.add(stringRequest);    }}



JacksonRequest---继承Request,重写deliverResponse方法,并调用ResponseListener的onResponse方法,并通过CacheManager.put(methodName, params, response);将获取的response缓存到CacheManager中。这一步很重要,调用我们自己的listener,而不是Volley提供给我们的Response.Listener
/** * Created by mcoy */public class JacksonRequest extends Request {    private final HashMap<String,String> params;    private final ResponseListener listener;    private final ObjectMapper mapper;    private final TypeReference javaType;   public JacksonRequest(String url,TypeReference javaType,HashMap<String,String> params,ResponseListener listener,Response.ErrorListener errorListener){       super(Method.POST,url,errorListener);       mapper = new ObjectMapper();       mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES,true);       mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);       this.params = params;       this.listener = listener;       this.javaType = javaType;   }    @Override    protected Map<String, String> getParams() throws AuthFailureError {        return params;    }    @Override    protected Response parseNetworkResponse(NetworkResponse response) {        String json;        try {            json = new String(response.data, HttpHeaderParser.parseCharset(response.headers));            PrintLog.log("返回的json:" + json);            return Response.success(mapper.readValue(json,javaType), HttpHeaderParser.parseCacheHeaders(response));        }catch (UnsupportedEncodingException e){            json = new String(response.data);            PrintLog.log("json:"+json);            try {                return Response.success(mapper.readValue(json,javaType),HttpHeaderParser.parseCacheHeaders(response));            } catch (IOException e1) {                return  Response.error(new ParseError(e));            }        } catch (JsonParseException e) {            PrintLog.log(e.toString());            return  Response.error(new ParseError(e));        } catch (JsonMappingException e) {PrintLog.log(e.toString());            return  Response.error(new ParseError(e));        } catch (IOException e) {PrintLog.log(e.toString());            return  Response.error(new ParseError(e));        }    }    @Override    protected void deliverResponse(Object response) {        listener.onResponse(response,true);    }}



ResponseListener---自定义的一个listener接口, 在发送请求时,需要将其实现。其中才参数中比Volley的提供的listener过了一个isCache的Boolean值,根据此值来决定是否要缓存。
/** * @version V1.0 <描述当前版本功能> * @author: mcoy */public interface ResponseListener<T> {    public void onResponse(T response, boolean isCache);}


更多相关文章

  1. 新版Cordova(>4.0)编译Android(安卓)APK打上签名方法
  2. Android(安卓)ListView/ListActivity点击长按事件
  3. 关于Android(安卓)webview 的cookie同步的坑
  4. Retrofit 2.0 超能实践,完美支持Https传输
  5. android分辨率与尺寸适配,UI切图方法
  6. android 之EditText长按屏蔽ActionMode context菜单但保留选择工
  7. Android之Intent附加数据的两种实现方法
  8. @InjectView的实例化
  9. AndroidJNI实践(1)-使用.h头文件-静态注册JNI方法

随机推荐

  1. Android(安卓)- 如何获取状态栏以及标题
  2. Project has no default.properties file
  3. Android(安卓)APP终极瘦身指南
  4. [置顶] OwnCloud开源项目之一导入Eclipse
  5. Android(安卓)极光推送
  6. 09 - android Spinner 下拉列表
  7. Ubuntu下使用Android实体机调试前需要修
  8. Android天气预报开发。
  9. 向Android中集成开源项目的一般步骤
  10. android sdk 让SDK Manager来自动安装上