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