软件编程
位置:首页>> 软件编程>> Android编程>> Android 中Volley二次封装并实现网络请求缓存

Android 中Volley二次封装并实现网络请求缓存

作者:Danny_姜  发布时间:2023-09-17 06:16:35 

标签:Android,Volley

Android 中Volley二次封装并实现网络请求缓存

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);
}

如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

来源:http://blog.csdn.net/zxm317122667/article/details/49634433

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com