当前位置: 移动技术网 > IT编程>移动开发>Android > Android 中Volley二次封装并实现网络请求缓存

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

2019年07月24日  | 移动技术网IT编程  | 我要评论

吉林医药学院吧,月上重火书包网,神魔十字架

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

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

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网