高效加载 Bitmap
2017-06-13 本文已影响78人
未见哥哥
在翻阅了 Universal-ImageLoader 源码之后,现在来总结一下如何高效加载 Bitmap 。在 Android 应用我们经常会看到使用 ListView 去加载大量的图片,而如果没有合理去加载 Bitmap 是很容易就造成内存溢出的。
举个例子
假如 ImageView 大小: 200*400
-
需要加载的图片大小 1080*1920
这样要把这么大的图片加载到 ImageView 上就完全没有必要了,而且很容易 oom -
假如图片采用 ARGB8888 格式存储的话,那么一个像素就占用了 4 个字节
108019204 = 7.9m 也就是说加载这么一张图片需要 7.9m 的空间。
压缩图片有四种方式:
BitmapFactory.decodeFile:针对文件系统
BitmapFactory.decodeResource:针对资源文件
BitmapFactory.decodeByteArray:针对字节数组
BitmapFactory.decodeStream:针对输入流
Bitmap 的高效加载其核心就是对需要加载图片进行压缩,使用 BitmapFactory.Option 来加载指定大小的图片。
操作步骤:
- options.inJustDecodeBounds = true;
设置该标记未 true 表示只加载 bitmap 的大小信息,并不会将整个 Bitmap 加载到内存中 - BitmapFactory.decodeXX(options)
- 根据得到的 options 计算 inSampleSize
注意:官方推荐这里的 inSampleSize 应该为 2 指数倍。 - options.inJustDecodeBounds = false;
设置该标记为 false 表示将 Bitamo 真正加载到内存中。 - Bitmap bmp = BitmapFactory.decodeXX(options)
示例代码
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher, opts);
//计算 inSampleSize
opts.inSampleSize = calculateInSampleSize(opts, 300, 300);
//加载 Bitmap 到内存中
opts.inJustDecodeBounds = false;
bmp = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher, opts);
//加载一张 Bitmap 显示在 ImageView
mImageView.setImageBitap(bmp)
/**
* 计算 inSampleSize
*
* @param opts
* @param reqWidth
* @param reqHeight
* @return
*/
private int calculateInSampleSize(BitmapFactory.Options opts, int reqWidth, int reqHeight) {
int inSampleSize = 1;
final int width = opts.outWidth;
final int height = opts.outHeight;
if (height > reqHeight || width > reqWidth) {
final int halfWidth = width / 2;
final int halfHeight = height / 2;
//500*800 1
//250*400 2
//125*200 4 不成立,最后 inSampleSize = 4
while (halfHeight / inSampleSize >= reqHeight && halfWidth / inSampleSize >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}