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

Android图片的三级缓存管理

2015-09-10 14:54 411 查看
Android的很多应用程序都有多图片的浏览功能,而图片多了很容易造成OOM,而且处理不好用户体验会很差,本文应用了一个硬缓存-软缓存-硬盘缓存的图片加载机制,来加快图片加载的速度和避免出现OOM。

一、设计分析:

1、硬缓存,在内存中级别最高,不会被GC回收的部分,使用LruCache;软存使用SoftReference,在内存中级别低于硬缓存,在内存紧张的时候会被GC回收;硬盘缓存使用DiskLruCache。对于lrucache与DiskLruCache不熟悉的,可参考http://blog.csdn.net/guolin_blog/article/details/34093441

2、实现原理,最近使用的图片存入LruCache中,在LruChche中被清除的图片放入软存,而全部图片都在硬盘中缓存一份。当需要加载图片时,先搜索LruCache,有直接返回,没有继续搜索SoftReference,如果有,先将图片取出在SoftReference中删除,存入LruCache并返回,没有继续搜索DiskLruCache,如果没有就开启任务去网络下载。下载完成后在LruCache中缓存一份,在DiskLruCache中缓存一份。

二、代码分析:

1、LruCache的初始化与设置

int maxMemory = (int) Runtime.getRuntime().maxMemory();
int cacheSize = maxMemory / 8; // 硬引用缓存容量,为系统分配内存的1/8
mLruCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
if (value != null)
return value.getRowBytes() * value.getHeight();
else
return 0;
}

@Override
protected void entryRemoved(boolean evicted, String key,
Bitmap oldValue, Bitmap newValue) {
if (oldValue != null)
// 硬引用缓存容量满的时候,会根据LRU算法把最近没有被使用的图片转入此软引用缓存
mSoftCache.put(key, new SoftReference<Bitmap>(oldValue));
}
};


LruCache的可缓存大小设置为本机为本应用开辟的最大内存的1/8,实现entryRemoved方法,在这里面将要被移除的图片加入软存中。

2、软存设置

软存使用LinkedHashMap配合SoftReference的形式

private LinkedHashMap<String, SoftReference<Bitmap>> mSoftCache;
private final int SOFT_CACHE_SIZE = 15;
mSoftCache = new LinkedHashMap<String, SoftReference<Bitmap>>(
SOFT_CACHE_SIZE, 0.75f, true) {

private static final long serialVersionUID = 1L;

@Override
protected boolean removeEldestEntry(
Entry<String, SoftReference<Bitmap>> eldest) {
if (size() > SOFT_CACHE_SIZE) {
return true;
}
return false;
}
};


这里设置软存的最大存储量是15个,重写removeEldestEntry方法,当图片数量多于15个时,销毁最早进入的图片。

3、硬盘缓存直接使用比较成熟稳定的DiskLruCache

/**
* 硬盘缓存版本
*/
private final int DISKLRU_VERSON = 1;
/**
* 硬盘缓存大小
*/
private final int DISKLRU_SIZE = 10 * 1024 * 1024;
/**
* 硬盘缓存文件名称
*/
private final String DISKLRU_NAME = "imagecache";
private DiskLruCache mDiskLruCache;
try {
// 获取图片缓存路径
File cacheDir = getDiskCacheDir(context, DISKLRU_NAME);
if (!cacheDir.exists()) {
cacheDir.mkdirs();
}
// 创建DiskLruCache实例,初始化缓存数据
mDiskLruCache = DiskLruCache.open(cacheDir,
Utils.getAppVersion(context), DISKLRU_VERSON, DISKLRU_SIZE);
} catch (IOException e) {
e.printStackTrace();
}


DiskLruCache不熟悉的可以参考

http://blog.csdn.net/guolin_blog/article/details/28863651

4、如果以上三步没有拿到bitmap,那么就要去网络下载了,本文使用AsyncTask下载。并使用set和List模仿一个简单的线程池,控制图片下载的并发数。具体代码参见:

http://download.csdn.net/detail/suyiyang888/9095027

水平有限,仅供参考。

感谢:

http://my.csdn.net/sinyu890807
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息