最近在学习Android中的图片缓存技术,所以选择记录一下常用的LruCache缓存技术。那些优秀的开源库中都使用了LruCache技术,因为我们在ListView、GridView等来显示图片的时候,他们都有很优秀的recycle机制但是我们就遇到如果ImageView被回收后下次再显示的话需要重新从网络或者本地读取图片,所以我们引入了LruCache技术。
在使用LruCache的时候我们需要考虑为LruCache分配多少空间的大小所以我们需要考虑这些点。
1.每一张图片大概能占用多少内存
2.应用能有多少内存可以允许分配
3.屏幕一下子需要显示多少张图片
当然这些考虑都是为了缓存空间的大小,避免分配太大的空间从而造成了java.lang.OutOfMemory异常。
首先我们需要初始化LruCache:
private void initLrucache() {
// 取现有内存的1/8 作为缓存空间大小 单位kb
int size = (int) (Runtime.getRuntime().maxMemory() / 1024) / 8;
mLruCache = new LruCache<String, Bitmap>(size){
@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getByteCount() / 1024;// 计算每张图片的内存大小
}
};
}
在LruCache中提供了put,get方法来存入和读取图片缓存,它的主要算法原理是把最近使用的对象用强引用存储在 LinkedHashMap 中,并且把最近最少使用的对象在缓存值达到预设定值之前从内存中移除。
开始下载一张图片,例子中使用的是drawable下放一张大图进行测试。
private void loadImage(int resId) {
// 从内存中读取Bitmap
Bitmap mBitmap = mLruCache.get(String.valueOf(resId));
if (mBitmap == null) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inPreferredConfig = Bitmap.Config.RGB_565;
BitmapFactory.decodeResource(getResources(), resId, options);
options.inSampleSize = BitmapUtil.calculateInsampleSize(options, 100, 100);
options.inJustDecodeBounds = false;
Log.w("Jayuchou", "options.inSampleSize === " + options.inSampleSize);
mBitmap = BitmapFactory.decodeResource(getResources(), resId, options);
// 把当前的Bitmap存入到Lrucache中
mLruCache.put(String.valueOf(resId), mBitmap);
}
mImageView.setImageBitmap(mBitmap);
}
因为我们知道在一个100*100dp的ImageView显示一张超大的图片有可能造成内存溢出从而得不偿失所以我们提供了calculateInsampleSize进行压缩图片处理。
public static int calculateInsampleSize(BitmapFactory.Options option, int reqWidth, int reqHeight) {
int width = option.outWidth;
int height = option.outHeight;
int inSampleSize = 1;
// 计算宽高的比例 且取更小的那个比例
if (width > reqWidth || height > reqHeight) {
int widthRatio = Math.round(width / reqWidth);
int heightRatio = Math.round(height / reqHeight);
inSampleSize = widthRatio > heightRatio ? heightRatio : widthRatio;
// 像一些额外的图片 例如全景图 使用上面的比重的出来的像素仍然很大 我们需要进一步再做处理
int totalPiexls = width * height;
int totalReqPiexls = reqWidth * reqHeight * 2;
while (totalPiexls / (inSampleSize * inSampleSize) > totalReqPiexls) {
inSampleSize ++;
}
}
return inSampleSize;
}
这样一张大图我们从下载好就put到LruCache中,下载要需要的时候直接从LruCache中直接读取速度更快,项目的体验更棒。我们这么处理当然就再也不怕一张大图造成内存溢出异常,这就是LruCache的技术优点。