Bitmap的有关讲解与优化:
1、有效处理较大的位图
- 图像有各种不同的形状和大小,在许多情况下,他们往往比一个典型的应用程序的用户界面UI所需要的资源更大
- 读取一个位图的尺寸和类型:
- 为了从多种资源来创建一个位图,BitmapFactory类提供了几个解码的方法(decodeByteArray()),decodeFile() ,decodeResource()等等
- 根据你的图像数据资源选择最合适的解码方式,这些方法视图请求分配内存来构造位图,因此很容易导致OOM异常,每种类型的解码方法都有
- 额外的特征可以让你通过BitMapFactory.Options方法指定解码选项,当解码时避免内存分配可以设置inJustDecodeBounds属性为true,位图对象返回null但是设置了outWidth,outHeight和outMimeType。这种技术允许你在创建位图(和分配内存)之前去读取图像的尺寸和类型
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(),R.id.myimage,options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
2、加载一个缩小版到内存中:
现在的图片尺寸都是已经知道的,他们可以被用来决定是否应该加载完整的图片到内存或者是否用一个缩小的版本去代替加载
以下是一些值得考虑的因素:
* 估计加载完整图片所需要的内存
* 你承诺加载的这个图片所需要的控件带给你的程序的其他内存需求
* 准备加载图像的目标imageview或者UI组件尺寸
* 当前设备的屏幕尺寸和密度例如。如果1024768像素的图像最终被缩略的显示在12896像素的imageview中,就不值得加载到内存中告诉解码器去重新采样这个图像,加载一个更小的版本到内存中,在你的BitmapFactory.Option对象中设置inSampleSize为true
例如,讲一个分辨率为20481536的图片用inSampleSize值为4去编码将产生一个大小为512384的位图,加载这个倒内存中仅使用0.75Mb,而不是一个完整的12mb大小的图片,(假设使用ARGB_8888位图的配置)。这里有一个方法在目标的宽度和高度的基础上来计算一个SampleSize的值。
/**
* 获取图片的采样比例
*/
public static int caculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
//获取位图的宽和高
final int height = options.outHeight;
final int widht = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || widht > reqWidth) {
if (widht > height) {
inSampleSize = Math.round((float) height / (float) reqHeight);
} else {
inSampleSize = Math.round((float) widht / (float) reqWidth);
}
}
return inSampleSize;
}
- 使用2的幂数设置inSampleSize的值可以是解码器更快,更有效,然而,如果你想在内存或这个硬盘中缓存一个图片调整后的版本通常解码到合适的图像尺寸更适合节省空间要使用这种方法。
- 首先解码,将inJustDecodeBounds摄者为true,将选项传递进去。
- 然后在次解码,在使用新的inSampleSize的值并将inJustDecodeBounds设置为false
/**
* 图片位图重新采样
*
* @param res
* @param resId
* @param reqWidth
* @param reqHeight
* @return
*/
public Bitmap decodeSampleFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId,options);
options.inSampleSize = caculateInSampleSize(options, reqWidth, reqHeight);
//再次解码
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId);
}
- 2、缓存位图
- 内存缓存
内存缓存体用了可以快速访问位图LruCache类用于缓存位图的任务,最近被引用给的对象保存在一个强引用LinkerHashMap中,以及在缓存超过了其指定的大小之前释放最近最少使用的对象的内存。
注意:在过去,一个常用的内存缓存实现是一个SoftReference或者WeakReference的位图缓存,然后现在不推荐使用,从2.3(API9)开始,垃圾回收器更加注重回收软/弱引用,着使得使用以上的引用很大程度上无效,此外,在3.0(API11)位图的备份很有可能会导致应用程序内存溢出和崩溃
- 内存缓存