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

}

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

以上是 Android 中Volley二次封装并实现网络请求缓存 的全部内容, 来源链接: utcz.com/z/329339.html

回到顶部