对于大尺寸图片加载,如何正常加载显示且不发生OOM?
图片采样的方法,是根据需要显示图片控件的大小对图片进行压缩显示。
主要用法
1、根据控件的宽高与原图的宽高的比例,计算出BitmapFactory.Options
中inSampleSize
值。例如:
public static int calculateInSampleSize(int reqWidth, int reqHeight, BitmapFactory.Options options) {
if (reqHeight == 0 || reqWidth == 0) {
return 1;
}
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;
// Calculate the largest inSampleSize value that is a power of 2 and
// keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) >= reqHeight
&& (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
Log.d(“TAG”, "calculateInSampleSize: " + inSampleSize);
return inSampleSize;
}
第一、二个参数分别是显示控件的宽度和高度,第三个参数是设置了inSampleSize的BitmapFactory.Options对象,设置inSampleSize为2的幂是因为解码器最终会对非2的幂的数进行向下处理,获取到最靠近2的幂的数。详情参考inSampleSize的文档。
2、然后在解析图片文件时,传入这个BitmapFactory.Options
。例如
public static Bitmap getFitSampleBitmap(String filePath, int width, int height) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, options);
//计算inSampleSize方法
options.inSampleSize = calculateInSampleSize(width, height, options);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(filePath, options);
}
第一个参数是图片存放的路径,第二、三个参数是显示控件的宽度和高度
测试过程,查看Memory使用情况
从上面对比可以看出,经过图片的采样压缩,内存使用大大降低,减少OOM的发生。
具体Demo可以参考Android 多种方式正确的加载图像,有效避免oom
对于世界地图等高清巨图,如果不压缩,那么按照原图尺寸加载,屏幕肯定不够,并且考虑内存的情况,不可能一次性将整图加载到内存中,否则很容易发生OOM。如何解决这种问题,可以采用的方法:局部加载,让图片按区域加载,用到Android提供的类:
BitmapRegionDecoder
主要用法:
1、创建BitmapRegionDecoder
对象
BitmapRegionDecoder
提供了一系列的newInstance方法来构造对象,传入需要处理的图片,支持传入文件路径,文件描述符,文件的inputstrem等。
例如:
BitmapRegionDecoder bitmapRegionDecoder =
BitmapRegionDecoder.newInstance(inputStream, false);
2、显示指定的区域
bitmapRegionDecoder.decodeRegion(rect, options);
参数一是一个rect,指定显示的区域,参数二是BitmapFactory.Options,可以控制图片的inSampleSize
, inPreferredConfig
等。
具体Demo可以学习Android 高清加载巨图方案 拒绝压缩图片,加上手势移动,动态修改显示的区域。
调试DEMO时,发现存在一个问题,初始化显示setInputStream
时,图片只显示一角,手势移动没有反应。
通过Debug,查到BitmapFactory.Options获取图片的宽高有问题,修改方式是直接通过BitmapRegionDecoder.getWidth和getHeight获取宽高。
参考资料
1、Android 多种方式正确的加载图像,有效避免oom
2、Android 高清加载巨图方案 拒绝压缩图片
3、Android图片尺寸与质量压缩你用对了吗?inSampleSize与quality的浅析