Android中加载大图片往往导致内存溢出,也就是OOM,这是为什么呢?因为android操作系统给每个应用程序分配了有限的内存,比如笔者测试的真机为应用程序分配的最大内存为96M(可以通过Runtime.getRuntime().maxMemory()函数获取到
),而Bitmap对象在内存中所占空间大小与图片本身的像素有关的。默认情况下,bitmap是ARGB_8888类型的,ARGB_8888是什么意思呢?ARGB8888:分别用8个bit来记录每个像素的A(透明度)、R(红色)、G(绿色)、B(蓝色)数据,就是常说的32bit位图,也就是每个像素占了4个字节,如果一张4000*4000的图片转化为bitmap对象,其所占内存空间算法为:4000*4000*4/(1024*1024)=61M(约数)。所以,如果在操作bitmap前不进行压缩,那么加载几张大图,就有可能导致内存溢出。
图片压缩主要分为质量压缩和尺寸压缩。通过算法同化了图片中的一些某个点附近相近的像素,以达到降低质量减少文件大小的目的,但它其实只能实现对file的构成影响,对加载这个图片出来的bitmap内存是无法节省的,因为质量压缩没有改变图片的像素,所以bitmap所占内存不变。
下面介绍这两种压缩技术的具体运用。
一、尺寸压缩:
BitmapFactory.Options类中有两个很重要的属性:inJustDecodeBounds和inSampleSize
。把inJustDecodeBounds属性设置为true就可以让解析方法禁止为bitmap分配内存,返回值也不再是一个Bitmap对象,而是null。虽然Bitmap是null了,但是BitmapFactory.Options的outWidth、outHeight和outMimeType属性都会被赋值。这个技巧让我们可以在加载图片之前就获取到图片的长宽值和MIME类型,从而根据情况对图片进行压缩。inSampleSize就是压缩的倍数,若inSampleSize=
1,表示不压缩,若为2,则表示压缩为原来尺寸的二分之一。
为了确定inSampleSize的大小,就要确定原来图片的大小和目标图片的比例,看代码:
public static int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
// 源图片的高度和宽度
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
// 计算出实际宽高和目标宽高的比率
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
/// 选择宽和高中最小的比率作为inSampleSize的值,这样可以保证最终图片的宽和高
// 一定都会大于等于目标的宽和高。
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
确定inSampleSize的大小后,便可调用
//尺寸压缩
public static Bitmap compressBitmapFromResBySize(Resources res, int resId,
int reqWidth, int reqHeight) {
// 第一次解析将inJustDecodeBounds设置为true,来获取图片大小
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 的内存大小,但是压缩后,保存在硬盘或者上传网络时,图片大小会变小,故有利于保存在硬盘或者上传服务器。
/**
* 质量压缩
* @param bitmap
* @return
*/
public static Bitmap compressBitmapByQuality(Bitmap bitmap){
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 60, bos);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
System.out.println("bis====="+bis.available());
return BitmapFactory.decodeStream(bis);
}
“`