在Android上面处理图片一直是一件很麻烦的事情,尤其是一些大图片,例如全景图的展示。
为什么说是一件麻烦的事情,主要有一下几个原因:
1.占内存,容易OOM
比如,一张1000 * 1000的图片,采用ARGB-8888的方式,这种方式,该图片每个px占用4个byte,所以总大小是1000 * 1000 * 4 ,它占用的内存就将近4M。这也不是一张很大的图片,但是却要占用4M内存。
2.使用UI主线程去加载大图片,非常耗APP的性能。很有可能出现响应慢,甚至是ANR的出现。
3.在加载多张图片的时候,如果没有使用缓存,app的流畅性和响应速度都会收到影响。
当然现在市面上也有很多开源框架来处理大图片,比如Glide、 Picasso等等.
但是,虽然我们没必要是重复造轮子,但是我们也有必要知道轮子是怎么造的。下面我们简单了解一下如何有效的展示一张大图。
一、bitmap,我们比较关注的是它的形状以及尺寸,那我们应该如何读取一张图片的形状和尺寸呢?直接看代码
//定义option
BitmapFactory.Options options = new BitmapFactory.Options();
//设置true,避免内存分配
options.inJustDecodeBounds = true;
//获取图片的宽和高
BitmapFactory.decodeResource(getResources(), R.id.image, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
//获取图片的形状
String imageType = options.outMimeType;
[BitmapFactory]提供了decoding方法,为了防止OOM,在decode之前一定要检查好尺寸。
二、计算合理的样本数据
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 halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / inSampleSize) >= reqHeight
&& (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
三、计算样本尺寸并decode
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// 检查尺寸
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// 计算样本尺寸
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// 按照样本尺寸decode图片
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
四、显示图片到ImageView
imageView.setImageBitmap(
decodeSampledBitmapFromResource(getResources(), R.id.image, 200, 200));
总结:这种方式可以轻松地将任意大尺寸的图片以200*200的缩略图的方式显示到ImageView上面。