在Android的开发过程中经常遇到多张大图片的加载,图片的类型是多种多样,不同大小。但是大多数的图片都是高分辨率,总体来说,远远大于我们要展示的容器ImageView。而加载过大图片就会导致OOM异常。下面就介绍解决该问题的途径
Android图片Bitmap对象是用BitmapFactory工具类中多种解析方法创建的。创建的方式大概分为:、
1)SD卡文件中加载解析方式
public static Bitmap decodeFile(String pathName, Options opts) {
}
2)资源中文件加载解析方式
public static Bitmap decodeResource(Resources res, int id, Options opts) {
}
3)字节数组解析方式
public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts) {
}
4)网络中加载流的解析方式
public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {
}
这些方法会尝试为已经构建的bitmap分配内存,这时就会很容易导致OOM出现。为此每一种解析方法都提供了一个可选的BitmapFactory.Options参数,将这个参数的inJustDecodeBounds属性设置为true就可以让解析方法禁止为bitmap分配内存,返回值也不再是一个Bitmap对象,而是null。虽然Bitmap是null了,但是BitmapFactory.Options的outWidth、outHeight和outMimeType属性都会被赋值。这个技巧让我们可以在加载图片之前就获取到图片的长宽值和MIME类型,从而根据情况对图片进行压缩。
/**
* 从SD卡中获取图片并且比例压缩
* @param path 路径
* @param mHeight 自定义高度
* @param mWidth 自定义宽度
* @return
*/
public static Bitmap getBitmapFromSDCard(String path, int mHeight, int mWidth)
{
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
//计算比例值
options.inSampleSize = calculateInSampleSize(options,mHeight,mWidth);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(path, options);
}
/**
* 计算压缩比例值inSampleSize
* @param options 压缩的参数设置
* @param mHeight 想要的高度
* @param mWidth 想要的宽度
* @return
*/
public static int calculateInSampleSize(BitmapFactory.Options options, int mHeight, int mWidth)
{
//原尺寸大小
int yHeight = options.outHeight;
int yWidth = options.outWidth;
int inSampleSize = 1;
//如果宽度大的话根据宽度固定大小缩放
if (yWidth > yHeight && yWidth > mWidth) {
inSampleSize = (int) (yWidth / mWidth);
}
//如果高度高的话根据宽度固定大小缩放
else if (yWidth < yHeight && yHeight > mHeight)
{
inSampleSize = (int) (yHeight / mHeight);
}
if (inSampleSize <= 0)
inSampleSize = 1;
return inSampleSize;
}
观察代码,可以看出,先后解析了两次图片,首先options.inJustDecodeBounds = true以后,BitmapFactory解析一次图片,将图片的得到的option传入到方法calculateInSampleSize方法中,在方法中可以根据ImageView控件的长宽对图片进行压缩,计算出合适的inSamplesize值,最后options.inJustDecodeBounds 设置 false以后,在对图片解析一次,这时的图片的比例值inSamplesize正是我们计算出来的值。
上面的这样做已经可以图片的比例压缩,至于有需要对图片质量压缩的可以参照一下代码。
/**
* 图片质量压缩(质量参数)
* @param image
* @param quality 质量参数 百分之多少 例如:0.6 0.7
* @return
*/
public static Bitmap compressImage(Bitmap image, float quality)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, (int)quality*100, baos);
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());// 把压缩后的数据baos存放到ByteArrayInputStream中
return BitmapFactory.decodeStream(isBm, null, null);// 把ByteArrayInputStream数据生成图片
}