如果每次加载同一张图片都要从网络获取,那代价实在太大了。所以同一张图片只要从网络获取一次就够了,然后在本地缓存起来,之后加载同一张图片时就从缓存中加载就可以了。从内存缓存读取图片是最快的,但是因为内存容量有限,所以最好再加上文件缓存。文件缓存空间也不是无限大的,容量越大读取效率越低,因此可以设置一个限定大小比如10M,或者限定保存时间比如一天。
因此,加载图片的流程应该是:
-
先从内存缓存中获取,取到则返回,取不到则进行下一步;
-
从文件缓存中获取,取到则返回并更新到内存缓存,取不到则进行下一步;
-
从网络下载图片,并更新到内存缓存和文件缓存。
接下来看内存缓存类:ImageMemoryCache
public class ImageMemoryCache {
/**
* 从内存读取数据速度是最快的,为了更大限度使用内存,这里使用了两层缓存。
* 硬引用缓存不会轻易被回收,用来保存常用数据,不常用的转入软引用缓存。
*/
private static final int SOFT_CACHE_SIZE = 15; //软引用缓存容量
private static LruCache<String, Bitmap> mLruCache; //硬引用缓存
private static LinkedHashMap<String, SoftReference<Bitmap>> mSoftCache; //软引用缓存
public ImageMemoryCache(Context context) {
int memClass = ((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();
int cacheSize = 1024 * 1024 * memClass / 4; //硬引用缓存容量,为系统可用内存的1/4
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));
}
};
mSoftCache = new LinkedHashMap<String, SoftReference<Bitmap>>(SOFT_CACHE_SIZE, 0.75f, true) {
private static final long serialVersionUID = 6040103833179403725L;
@Override
protected boolean removeEldestEntry(Entry<String, SoftReference<Bitmap>> eldest) {
if (size() > SOFT_CACHE_SIZE){
return true;
}
return false;
}
};
}
/**
* 从缓存中获取图片
*/
public Bitmap getBitmapFromCache(String url) {
Bitmap bitmap;
//先从硬引用缓存中获取
synchronized (mLruCache) {
bitmap = mLruCache.