欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2023-12-16 15:52:16
android 中volley二次封装并实现网络请求缓存 android目前很多同学使用volley请求网络数据,但是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); 
} 

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

上一篇:

下一篇: