Android 中Volley二次封装并实现网络请求缓存
Android中Volley二次封装并实现网络请求缓存
Android目前很多同学使用Volley请求网络数据,但是Volley没有对请求过得数据进行缓存,因此需要我们自己手动缓存。一下就是我的一种思路,仅供参考
具体使用方法为:
HashMapparams=newHashMap<>(); params.put("id","1"); params.put("user","mcoy"); newNetWorkHelper(getActivity()).jacksonMethodRequest ("method_id",params,newTypeReference >(){},handler,msgId);
NetWorkHelper---对Volley的封装,首先调用CacheManager.get(methodName,params);方法获取缓存中的数据,如果数据为null,
则继续发送网络请求。
/** *@versionV1.0网络请求帮助类 *@author:mcoy */ publicfinalclassNetWorkHelper{ privateNetWorkManagernetWorkUtils; publicNetWorkHelper(Contextcontext){ netWorkUtils=newNetWorkManager(context); } publicstaticfinalStringCOMMON_ERROR_MSG="连接超时,请稍后重试"; publicstaticfinalintCOMMON_ERROR_CODE=2; /** *使用Jackson请求的方法 *@parammethodName *@paramparams *@paramhandler *@parammsgId */ publicvoidjacksonMethodRequest(finalStringmethodName,finalHashMapparams,TypeReferencejavaType,finalHandlerhandler,finalintmsgId){ ResponseListenerlistener=newResponseListener(){ @Override publicvoidonResponse(Objectresponse,booleanisCache){ PrintLog.log(response.toString()); if(isCache){ CacheManager.put(methodName,params,response); } if(handler!=null){ Messagemessage=handler.obtainMessage(); message.what=msgId; message.obj=response; handler.sendMessage(message); } } }; Objectrespone=CacheManager.get(methodName,params); if(respone!=null){ listener.onResponse(respone,false); return; } HashMap allParams=Config.setSign(true); allParams.putAll(params); Response.ErrorListenererrorListener=newResponse.ErrorListener(){ @Override publicvoidonErrorResponse(VolleyErrorerror){ error.printStackTrace(); if(handler!=null){ Messagemessage=handler.obtainMessage(); message.what=msgId; message.obj=COMMON_ERROR_MSG; handler.sendMessage(message); } } }; netWorkUtils.jacksonRequest(getUrl(methodName),allParams,javaType,listener,errorListener); } /** *Url直接请求 *@paramurl *@paramparams *@paramhandler *@parammsgId */ publicvoidurlRequest(Stringurl,HashMap params,JsonParserjsonParser,finalHandlerhandler,finalintmsgId){ request(url,true,params,jsonParser,handler,msgId); } /** *通过方法请求 *@parammethodName方法名 *@paramparams请求参数 *@paramjsonParserJson解析器 *@paramhandler回调通知 *@parammsgId通知的Id */ publicvoidmethodRequest(StringmethodName,finalHashMap params,finalJsonParserjsonParser,finalHandlerhandler,finalintmsgId){ request(getUrl(methodName),true,params,jsonParser,handler,msgId); } /** *通过方法请求 *@parammethodName方法名 *@paramparams请求参数 *@paramjsonParserJson解析器 *@paramhandler回调通知 *@parammsgId通知的Id */ publicvoidmethodRequest(StringmethodName,booleanisLogin,finalHashMap params,finalJsonParserjsonParser,finalHandlerhandler,finalintmsgId){ request(getUrl(methodName),isLogin,params,jsonParser,handler,msgId); } privatevoidrequest(finalStringurl,booleanisLogin,finalHashMap params,finalJsonParserjsonParser,finalHandlerhandler,finalintmsgId){ finalHashMap allParams=Config.setSign(isLogin); allParams.putAll(params); Response.Listenerlistener=newResponse.Listener (){ @Override publicvoidonResponse(Stringresponse){ /** *有些请求默认是没有parser传过来的,出参只求String,譬如联合登录等 *所以加了一个elseif */ Objectresult; PrintLog.log(response); if(jsonParser!=null){ jsonParser.json2Obj(response); jsonParser.temple.description=jsonParser.temple.getResultDescription(); result=jsonParser.temple; }else{ ReturnTempletemple=newReturnTemple(); temple.issuccessful=false; temple.description=COMMON_ERROR_MSG; temple.result=-100; result=temple; } if(handler!=null){ Messagemessage=handler.obtainMessage(); message.what=msgId; message.obj=result; handler.sendMessage(message); } } }; Response.ErrorListenererrorListener=newResponse.ErrorListener(){ @Override publicvoidonErrorResponse(VolleyErrorerror){ Objectresult; if(jsonParser!=null){ ReturnTempletemple=newReturnTemple(); temple.issuccessful=false; temple.description=COMMON_ERROR_MSG; temple.result=COMMON_ERROR_CODE; result=temple; }else{ result=COMMON_ERROR_MSG; } if(handler!=null){ Messagemessage=handler.obtainMessage(); message.what=msgId; message.obj=result; handler.sendMessage(message); } } }; netWorkUtils.request(url,allParams,listener,errorListener); } /** *根据访求名拼装请求的Url *@parammethodName *@return */ privateStringgetUrl(StringmethodName){ Stringurl=Config.getUrl(); if(!StringUtil.isNullOrEmpty(methodName)){ url=url+"?method="+methodName; } returnurl; } }
CacheManager---将针对某一method所请求的数据缓存到本地文件当中,主要是将CacheRule写到本地文件当中
/** *@versionV1.0<缓存管理> *@author:mcoy */ publicfinalclassCacheManager{ /** *一个方法对应的多个Key,比如分类都是同一个方法,但是请求会不一样,可能都要缓存 */ privatestaticHashMap>methodKeys; privatestaticfinalStringkeyFileName="keys.pro"; /** *读取缓存的Key */ publicstaticvoidreadCacheKey(){ methodKeys=(HashMap >)readObject(keyFileName); if(methodKeys==null){ methodKeys=newHashMap >(); } } /** *保存缓存 */ publicstaticvoidput(Stringmethod,HashMap params,Objectobject){ longexpireTime=CacheConfig.getExpireTime(method); if(expireTime<=0||methodKeys==null){//有效时间小于0,则不需要缓存 return; } Stringkey=createKey(method,params); if(methodKeys.containsKey(method)){ ArrayList keys=methodKeys.get(method); keys.add(key); }else{ ArrayList keys=newArrayList<>(); keys.add(key); methodKeys.put(method,keys); } writeObject(methodKeys,keyFileName); StringfileName=key+".pro"; CacheRulecacheRule=newCacheRule(expireTime,object); LogModel.log("put"+method+""+key+""+cacheRule); writeObject(cacheRule,fileName); } publicstaticObjectget(Stringmethod,HashMap params){ longexpireTime=CacheConfig.getExpireTime(method); if(expireTime<=0||methodKeys==null||!methodKeys.containsKey(method)){//有效时间小于0,则不需要缓存 returnnull; } ArrayList keys=methodKeys.get(method); //StringsaveKey=keys.get(method); Stringkey=createKey(method,params); StringfileName=key+".pro"; //LogModel.log("get"+method+""+(saveKey.equals(key))+"path:"+fileName); CacheRulecacheRule=null; try{ if(keys.contains(key)){ cacheRule=(CacheRule)readObject(fileName); } }catch(Exceptione){ e.printStackTrace(); } LogModel.log("get:"+method+""+key+""+cacheRule); if(cacheRule!=null&&cacheRule.isExpire()){ returncacheRule.getData(); }else{ returnnull; } } publicstaticvoidmain(String[]args){ Stringmethod="category.getCategory"; HashMap params=newHashMap<>(); params.put("categoryId","-3"); System.out.println(createKey(method,params)); System.out.println(CacheRule.getCurrentTime()); } /** *生成Key * *@parammethod请求的方法名 *@paramparams私有参数(除公共参数以外的参数) *@return */ privatestaticStringcreateKey(Stringmethod,HashMap params){ try{ MessageDigestdigest=MessageDigest.getInstance("md5"); digest.digest(method.getBytes("UTF-8")); StringBuilderbuilder=newStringBuilder(method); if(params!=null&¶ms.size()>0){ Iterator >iterator=params.entrySet().iterator(); while(iterator.hasNext()){ Map.Entry entry=iterator.next(); builder.append(entry.getKey()).append("=").append(entry.getValue()); } } byte[]tempArray=digest.digest(builder.toString().getBytes("UTF-8")); StringBufferkeys=newStringBuffer(); for(byteb:tempArray){ //与运算 intnumber=b&0xff;//加盐 Stringstr=Integer.toHexString(number); //System.out.println(str); if(str.length()==1){ keys.append("0"); } keys.append(str); } returnkeys.toString().toUpperCase(); }catch(Exceptione){ e.printStackTrace(); } returnmethod.toUpperCase(); } /** *将对象写到文件中 * *@paramobject *@paramfileName */ privatestaticvoidwriteObject(Objectobject,StringfileName){ try{ ObjectOutputStreamoo=newObjectOutputStream(newFileOutputStream(newFile(CacheConfig.getCachePath()+fileName))); oo.writeObject(object); oo.close(); }catch(IOExceptione){ e.printStackTrace(); } } /** *读取对象 * *@paramfileName *@return */ privatestaticObjectreadObject(StringfileName){ Objectresult=null; try{ Filefile=newFile(CacheConfig.getCachePath()+fileName); if(file.exists()){ ObjectInputStreamoi=newObjectInputStream(newFileInputStream(file)); result=oi.readObject(); oi.close(); } }catch(Exceptione){ e.printStackTrace(); } returnresult; } }
CacheConfig---初始化哪些方法需要做缓存处理,以及缓存的有效时间
/** *@versionV1.0<设置哪些类数据需要缓存> *@author:mcoy */ publicfinalclassCacheConfig{ /**方法对应的缓存有效时间,时间是毫秒*/ privatestaticHashMapmethodExpireTimes=newHashMap (); privatestaticStringcachePath=null; static{ methodExpireTimes.put(ConstMethod.GET_CATEGORY_LIST,30*60*1000L); methodExpireTimes.put(ConstMethod.GET_NEW_CATEGORY_LIST,30*60*1000L); } /** *初始化缓存路径 *@paramcontext */ publicstaticvoidinit(Contextcontext){ cachePath=context.getFilesDir().getPath()+File.separator+"cache"+File.separator; Filefile=newFile(cachePath); if(!file.exists()){ file.mkdirs(); } CacheManager.readCacheKey(); } /**缓存路径*/ publicstaticStringgetCachePath(){ returncachePath; } /** *获取有方法对应的有效时间,如果方法没有添加缓存或者缓存时间小于0,则不添加缓存 *@parammethod *@return */ publicstaticlonggetExpireTime(Stringmethod){ if(methodExpireTimes.containsKey(method)){ returnmethodExpireTimes.get(method); }else{ return-1; } } }
CacheRule---主要有两个参数,expireTime需要缓存的时间,data需要缓存的数据
publicclassCacheRuleimplementsSerializable{ /**有效时间*/ publiclongexpireTime; /**缓存时间*/ publiclongcacheTime; /**缓存数据*/ privateObjectdata; publicCacheRule(longexpireTime,Objectdata){ cacheTime=getCurrentTime(); this.expireTime=expireTime; this.data=data; } publicObjectgetData(){ returndata; } publicvoidsetData(Objectdata){ this.data=data; } @Override publicinthashCode(){ returnBeanTools.createHashcode(expireTime,cacheTime,data); } @Override publicStringtoString(){ StringBuilderbuilder=newStringBuilder(); 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()); returnbuilder.toString(); } /** *数据是否有效 *@return */ publicbooleanisExpire(){ longcurTime=getCurrentTime(); returncurTime>(expireTime+cacheTime)?false:true; } /** *获取当前时间 *@return */ publicstaticlonggetCurrentTime(){ //if(Build.VERSION_CODES.JELLY_BEAN_MR1<=Build.VERSION.SDK_INT){ //returnSystemClock.elapsedRealtimeNanos(); //}else{ returnSystem.currentTimeMillis(); //} } }
NetWorkManager---往RequestQueue中添加JacksonRequest请求,然后Volley会去请求数据
/** *网络请求的工具类 */ publicfinalclassNetWorkManager{ privateRequestQueuerequestQueue; publicNetWorkManager(Contextcontext){ requestQueue=Volley.newRequestQueue(context); } /** *使用Jackson解析请求的方法 *@paramurl *@paramparams *@paramjavaType成功时返回的Java类型 *@paramlistener *@paramerrorListener */ publicvoidjacksonRequest(finalStringurl,finalHashMapparams,TypeReferencejavaType,ResponseListenerlistener,Response.ErrorListenererrorListener){ JacksonRequestjacksonRequest=newJacksonRequest(url,javaType,params,listener,errorListener); requestQueue.add(jacksonRequest); } /** *普通的网络请求,返回的Json *@paramurl *@paramparams *@paramlistener *@paramerrorListener */ publicvoidrequest(finalStringurl,finalHashMap params,Response.Listenerlistener,Response.ErrorListenererrorListener){ StringRequeststringRequest=newStringRequest(Request.Method.POST,url,listener,errorListener){ @Override protectedMap getParams()throwsAuthFailureError{ if(PrintLog.DEBUG){ Iterator >iterator=params.entrySet().iterator(); StringBuilderbuilder=newStringBuilder(url+""); while(iterator.hasNext()){ Map.Entry entry=iterator.next(); builder.append(entry.getKey()+":"+entry.getValue()).append(";"); } PrintLog.log(builder.toString()); } returnparams; } }; requestQueue.add(stringRequest); } }
JacksonRequest---继承Request,重写deliverResponse方法,并调用ResponseListener的onResponse方法,并通过CacheManager.put(methodName,params,response);将获取的response缓存到CacheManager中。这一步很重要,调用我们自己的listener,而不是Volley提供给我们的Response.Listener
/** *Createdbymcoy */ publicclassJacksonRequestextendsRequest{ privatefinalHashMapparams; privatefinalResponseListenerlistener; privatefinalObjectMappermapper; privatefinalTypeReferencejavaType; publicJacksonRequest(Stringurl,TypeReferencejavaType,HashMap params,ResponseListenerlistener,Response.ErrorListenererrorListener){ super(Method.POST,url,errorListener); mapper=newObjectMapper(); 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 protectedMap getParams()throwsAuthFailureError{ returnparams; } @Override protectedResponseparseNetworkResponse(NetworkResponseresponse){ Stringjson; try{ json=newString(response.data,HttpHeaderParser.parseCharset(response.headers)); PrintLog.log("返回的json:"+json); returnResponse.success(mapper.readValue(json,javaType),HttpHeaderParser.parseCacheHeaders(response)); }catch(UnsupportedEncodingExceptione){ json=newString(response.data); PrintLog.log("json:"+json); try{ returnResponse.success(mapper.readValue(json,javaType),HttpHeaderParser.parseCacheHeaders(response)); }catch(IOExceptione1){ returnResponse.error(newParseError(e)); } }catch(JsonParseExceptione){ PrintLog.log(e.toString()); returnResponse.error(newParseError(e)); }catch(JsonMappingExceptione){PrintLog.log(e.toString()); returnResponse.error(newParseError(e)); }catch(IOExceptione){PrintLog.log(e.toString()); returnResponse.error(newParseError(e)); } } @Override protectedvoiddeliverResponse(Objectresponse){ listener.onResponse(response,true); } }
ResponseListener---自定义的一个listener接口,在发送请求时,需要将其实现。其中才参数中比Volley的提供的listener过了一个isCache的Boolean值,根据此值来决定是否要缓存。
/** *@versionV1.0<描述当前版本功能> *@author:mcoy */ publicinterfaceResponseListener{ publicvoidonResponse(Tresponse,booleanisCache); }
如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!