转载请注明原文地址:http://blog.csdn.net/mxm691292118/article/details/51028953
我把Android重难点和读书笔记都整理在github上:https://github.com/miomin/AndroidDifficulty
如果你觉得对你有帮助的话,希望可以star/follow一下哟,我会持续保持更新。
写在前面:笔者的上一篇博文有提到过,如果不恰当的使用Bitmap,很容易造成OOM。这篇博文就来谈谈应该如何正确的管理Bitmap的内存,以及优化策略。
参考: Google官方教程 – 《Android Training Ccourse》
一、加载按显示需要的比例缩小的图片
1、先来说说屏幕密度
在Android中,Imageview控件的长宽单位一般设置为dp/dip,而不用px。这样做的原因,是因为dp/dip与屏幕像素密度无关,px与屏幕密度有关。在Android中,规定以160dpi为基准,1dip=1px,如果密度是320dpi,则1dip=2px。(所以,同一个imageview,在不同的设备上所显示的长宽的像素是不同的,我们需要根据像素不同,来按比例压缩大图)
如果把一个大小为1024x1024像素的图片显示到大小为512x512像素的ImageView上吗,就没有必要加载整张原图到Bitmap中。
为了告诉解码器去加载一个缩小比例是多少的图片到内存中,需要在BitmapFactory.Options 中设置 inSampleSize 的值。例如, 一个分辨率为2048x2048的图片,如果设置 inSampleSize 为4,那么会产出一个大约512x512大小的Bitmap。
下面的代码是动态获取一个ImageView的长宽像素:
注意:返回的是像素值(px),而不是dp/dip
int reqHeight = iv.getLayoutParams().height;
int reqWidth = iv.getLayoutParams().width;
2、压缩图片
- 一般来说,加载本地资源图片才需要压缩,加载网络图片,应该让服务器按需压缩,一方面节省流量,另一方面提高加载流畅度
- 可以通过下面的代码计算inSampleSize的值,就是需要压缩的倍数:
//reqWidth和reqHeight是需要显示的Imageview的width和height
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// height和width图片长宽的像素
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
- 通过下面的方法可以获得压缩后的Bitmap:
注意:可以通过设置 inJustDecodeBounds 属性为true可以在解码的时候避免内存的分配,它会返回一个null的Bitmap,但是可以获取到 outWidth, outHeight 与 outMimeType。确定好压缩比例后,再将inJustDecodeBounds设置为false。
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// 计算inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// 根据inSampleSize压缩图片
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
二、Bitmap缓存
1、缓存类LruCache介绍
- 在Android3.0之后,一般使用LruCache来缓存Bitmap,它使用一个强引用的LinkedHashMap保存最近引用的对象,并且在缓存超出设置大小的时候剔除(evict)最少使用到的对象。
- LinkedHashMap会根据LRU算法来排列对象的顺序,新加入的对象添加到头部,刚被使用过的对象也被移动到头部,所以在链表尾部的对象是最久没有被使用过的,一旦链表满了,有新对象加入,就会删除链表尾部的对象。
2、如何给LruCache设置一个合适的大小?
- LruCache太大的话,容易造成OOM或者分配给应用的剩余内存不够用,LruCache大小的设置,应该考虑下面的因素:
- (1)应用允许的最大内存是多少?剩下了多少可用的内存?
- (2)多少张图片会同时显示在屏幕上?</