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;
}
HashMapallParams=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,HashMapparams,JsonParserjsonParser,finalHandlerhandler,finalintmsgId){
request(url,true,params,jsonParser,handler,msgId);
}
/**
*通过方法请求
*@parammethodName方法名
*@paramparams请求参数
*@paramjsonParserJson解析器
*@paramhandler回调通知
*@parammsgId通知的Id
*/
publicvoidmethodRequest(StringmethodName,finalHashMapparams,finalJsonParserjsonParser,finalHandlerhandler,finalintmsgId){
request(getUrl(methodName),true,params,jsonParser,handler,msgId);
}
/**
*通过方法请求
*@parammethodName方法名
*@paramparams请求参数
*@paramjsonParserJson解析器
*@paramhandler回调通知
*@parammsgId通知的Id
*/
publicvoidmethodRequest(StringmethodName,booleanisLogin,finalHashMapparams,finalJsonParserjsonParser,finalHandlerhandler,finalintmsgId){
request(getUrl(methodName),isLogin,params,jsonParser,handler,msgId);
}
privatevoidrequest(finalStringurl,booleanisLogin,finalHashMapparams,finalJsonParserjsonParser,finalHandlerhandler,finalintmsgId){
finalHashMapallParams=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,HashMapparams,Objectobject){
longexpireTime=CacheConfig.getExpireTime(method);
if(expireTime<=0||methodKeys==null){//有效时间小于0,则不需要缓存
return;
}
Stringkey=createKey(method,params);
if(methodKeys.containsKey(method)){
ArrayListkeys=methodKeys.get(method);
keys.add(key);
}else{
ArrayListkeys=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,HashMapparams){
longexpireTime=CacheConfig.getExpireTime(method);
if(expireTime<=0||methodKeys==null||!methodKeys.containsKey(method)){//有效时间小于0,则不需要缓存
returnnull;
}
ArrayListkeys=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";
HashMapparams=newHashMap<>();
params.put("categoryId","-3");
System.out.println(createKey(method,params));
System.out.println(CacheRule.getCurrentTime());
}
/**
*生成Key
*
*@parammethod请求的方法名
*@paramparams私有参数(除公共参数以外的参数)
*@return
*/
privatestaticStringcreateKey(Stringmethod,HashMapparams){
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.Entryentry=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,finalHashMapparams,Response.Listenerlistener,Response.ErrorListenererrorListener){
StringRequeststringRequest=newStringRequest(Request.Method.POST,url,listener,errorListener){
@Override
protectedMapgetParams()throwsAuthFailureError{
if(PrintLog.DEBUG){
Iterator>iterator=params.entrySet().iterator();
StringBuilderbuilder=newStringBuilder(url+"");
while(iterator.hasNext()){
Map.Entryentry=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,HashMapparams,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
protectedMapgetParams()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); }
如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!