您的位置:首页 > 移动开发 > Android开发

10分钟教你学会三级缓存

2016-05-27 13:25 302 查看

一、开篇序言

网上很多图片三级缓存的文章,这里讲的是Json缓存,这类文章网上缺乏,有必要分享分享。

二、先上图,看效果



二、分析LruCache如何缓存数据

上图是完整的三级缓存的Demo,内存缓存使用LruCache,SD卡缓存使用数据库(当然你缓存到文件也可以)。

LruCache既然可以缓存到内存?没错,LruCache不只是可以缓存图片,还可以缓存数据到内存。

LruCache这个类不是第三方提供的,android API自带,建议使用v4包里面的(android.support.v4.util.LruCache)

使用LruCache存储数据

int maxSize = 10;//缓存最大值:10byte(字节),UTF-8中,每个英文字母占一个byte
LruCache<String, String> lruCache = new LruCache<String, String>(maxSize) {
/**计算大小*/
@Override
protected int sizeOf(String key, String value) {
return value.getBytes().length;//字符串长度
}
};
lruCache.put("1", "AAA");
lruCache.put("2", "BBB");
lruCache.put("3", "CCC");
print(lruCache);//print方法在下面
lruCache.put("4", "DDD");
print(lruCache);
String value = lruCache.get("3");//key位3的value是CCC
print(lruCache);


打印结果(附上分析)

<pre name="code" class="java">------------------start------------------
key=1,value=AAA
key=2,value=BBB
key=3,value=CCC
-------------------end-----------------
------------------start------------------
key=2,value=BBB
key=3,value=CCC
key=4,value=DDD   //分析:put("DDD")后,存储空间变成12byte,超出我们设置最大值10byte,所有删除最近最少使用的"AAA"
-------------------end-----------------
------------------start------------------
key=2,value=BBB
key=4,value=DDD
key=3,value=CCC  //分析:CCC顺序和之前不一样,因为上面第15行代码访问了CCC,LruCache内部维护LinkHashMap集合,会对集合进行LRU算法排序。
-------------------end-----------------




print方法:

/**打印集合 */
private void print(LruCache<String, String> lruCache) {
LogUtil.d("------------------start------------------");
Map<String, String> snapshot = lruCache.snapshot();
for (Map.Entry<String, String> entry : snapshot.entrySet()) {
LogUtil.d("key=" + entry.getKey() + ",value=" + entry.getValue());
}
LogUtil.d("-------------------end-----------------");
}
综上所述:

1.LruCache可以缓存数据,不只是缓存图片,而且LruCache内部维护了Map集合,所有我们的数据其实是缓存到了内存中

2.LruCache内部使用LRU算法对数据排序

上面的分析是为了下面Demo做知识储备,学会了这个内容,下面正式进入到项目中

三、结合LruCache处理三级缓存

3.1网络层

这里使用谷歌的Volley请求网络,每次获取网络数据并存储到内存中。LruCache的key是页码,value是每页数据
/**从网络获取数据*/
private void getDataFromInternet(String reqFlag, RequestQueue queue, final int pagenum, final Response.Listener<String> listener, Response.ErrorListener errListener) {
StringRequest request = new StringRequest(url + "?pagenum=" + pagenum, new Response.Listener<String>() {
@Override
public void onResponse(String data) {
listener.onResponse(data);//返回给Activity
//拿到数据,缓存到内存
storeToMemory(pagenum, data);
showToast("从网络获取第" + pagenum + "页数据");
}
}, errListener);
request.setTag(reqFlag);
queue.add(request);//发起网络请求
}

3.2内存层

内存使用了LruCache,内存层主要工作:将网络数据存储到内存,从内存中获取数据,如下:

1.判断内存有没有数据

private boolean exitInMemory(int pagenum){
if(lruCache == null) return false;
String data = lruCache.get(pagenum + "");
return !TextUtils.isEmpty(data);
}

2.获取内存数据

public String getDataFromMemory(int pagenum){
return lruCache.get(pagenum + "");
}

3.将网络数据存储到内存

/**将数据存储到内存*/
public void storeToMemory(int pagenum, String data){
//lrucache设置最大值:MEMORY_MAX_SIZE=4000(byte)
if(lruCache == null) lruCache = new LruCache<String, String>(MEMORY_MAX_SIZE){
@Override
protected int sizeOf(String key, String value) {
return value.getBytes().length;//计算每次存入内容大小
}
};
//存储到内存
lruCache.put(pagenum + "", data);//key是页码,每一页数据是value
LogUtil.d("内存数据大小=" + lruCache.size());//test
print();//test
}


3.3网络结合内存提高用户体验

/**获取酒店列表数据*/
public void getHotelList(String reqFlag, RequestQueue queue, final int pagenum, final Response.Listener<String> listener, Response.ErrorListener errListener){
if(exitInMemory(pagenum)){//如果内存中存在,直接返回内存数据
String data = getDataFromMemory(pagenum);
listener.onResponse(data);//回调给UI
}else {//从网络获取数据
getDataFromInternet(reqFlag, queue, pagenum, listener, errListener);
}
}


3.4最后一层:SD卡

为了篇幅言简意赅,这里不再分析如何缓存Json到SD卡。给大家提供参考思路,或者直接下载完整Demo参考。
思路:高德地图使用了DiskLruCache将数据缓冲到SD卡,不使用LruCache算法缓存到文件或者数据库都没问题,看需求。内存中使用了LruCache,所以SD卡可以不使用LRU。

四、Demo下载地址

客户端Demo:https://github.com/jiyouliang/DataStorage
依赖的服务器代码:https://github.com/jiyouliang/VolleyTest
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息