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); }
如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!