0%

Android获取图片压缩后的Bitmap避免OOM

OOM即Out Of Memory的简称,Android平台避免OOM异常的发生是非常有必要的。而在Android中加载大量大图便可能会导致OOM异常的出现,解决的办法之一就是加载图片之前对图片进行压缩然后再获取图片对应的Bitmap对象,那么应该如何操作呢? 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/**
* 通过图片的绝对路径来获取对应的压缩后的Bitmap对象
*/
public static Bitmap getCompressedBitmap(String filePath, int requireWidth,
int requireHeight) {
// 第一次解析将inJustDecodeBounds设置为true,用以获取图片大小,并且不需要将Bitmap对象加载到内存中
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, options); // 第一次解析
// 计算inSampleSize的值,并且赋值给Options.inSampleSize
options.inSampleSize = calculateInSampleSize(options, requireWidth,
requireHeight);
// 使用获取到的inSampleSize再次解析图片
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(filePath, options);
}

/**
* 通过图片资源id获取图片对应的压缩后的Bitmap对象
*/
public static Bitmap getCompressedBitmap(Resources res, int resId, int requiredWidth, int requiredHeight) {

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;

BitmapFactory.decodeResource(res, resId, options);// 第一次解析
options.inSampleSize = calculateInSampleSize(options, requiredWidth,
requiredHeight);

options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);// 第一次解析
}

/**
* 计算压缩的inSampleSize的值,该值会在宽高上都进行压缩(也就是压缩前后比例是inSampleSize的平方倍)
*/
private static int calculateInSampleSize(BitmapFactory.Options options,
int requireWidth, int requireHeight) {
// 获取源图片的实际的宽度和高度
int realWidth = options.outWidth;
int realHeight = options.outHeight;

int inSampleSize = 1;
if (realWidth > requireWidth || realHeight > requireHeight) {
// 计算出实际的宽高与目标宽高的比例
int widthRatio = Math.round((float) realWidth
/ (float) requireWidth);
int heightRatio = Math.round((float) realHeight
/ (float) requireHeight);
// 选择宽高比例最小的值赋值给inSampleSize,这样可以保证最终图片的宽高一定会大于或等于目标的宽高
inSampleSize = widthRatio < heightRatio ? widthRatio : heightRatio;
}
return inSampleSize;
}

以上代码中,有一点值得商榷
到底是要让图片显示完全还是让图片宽高和需要的宽高一致呢?
如果需要让图片宽高和需要的宽高一致的话,就选择比率小的:

1
inSampleSize = widthRatio < heightRatio ? widthRatio : heightRatio;

如果需要让图片显示完全的话,就选择比率大的:

1
inSampleSize = widthRatio > heightRatio ? widthRatio : heightRatio;

如果两者都要兼顾的话,就让方法多设置参数,让调用者决定去吧! :)

参考链接:
Displaying Bitmaps Efficiently
Android高效加载大图、多图解决方案,有效避免程序OOM