转载请标明出处:http://blog.csdn.net/goldenfish1919/article/details/37654697
原文:http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
图片可以有各种各样的形状和大小。很多时候,他们会比UI需要的要大。比如说系统的画廊应用,它用来展示设备上用摄像头拍摄的照片,这些照片的分辨率一般会远远高于设备屏幕的密度。
假如你可用的内存是有限的,理想的情况是你只需要在内存中载入一个低分辨率的版本。这个低分辨率的版本应该跟展示它的UI的大小相匹配。过高分辨率的图片并不会提供任何视觉上的好处,但是,却仍会占据宝贵的内存,带来因缩放导致的额外性能开销。
本文带你学习如何解码大的图片,在内存中载入小的子副本,使它不会超过应用的内存限制。
获取Bitmap的尺寸和类型
BitmapFactory类提供了很多解码方法(decodeByteArray(), decodeFile(), decodeResource(),等)用来从各种数据源创建一个Bitmap。要根据你的图片的数据来源选择最合适的解码方法。这些方法会尝试给构造出来的bitmap分配内存,因此很容易就会导致OutOfMemory。每一种类型的解码方法都有一个额外的签名参数用来让你通过BitmapFactory.Options类指定解码选项。在解码的时候,把inJustDecodeBounds属性设置成true会避免内存分配,返回的结果bitmap是null,但是却设置了outWidth, outHeight and outMimeType。这种技术允许你在构造bitmap(并分配内存)之前能获取图片的尺寸和类型。
BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(getResources(), R.id.myimage, options); int imageHeight = options.outHeight; int imageWidth = options.outWidth; String imageType = options.outMimeType;为了避免java.lang.OutOfMemory,在解码图片之前,要检查bitmap的尺寸,除非你能绝对信任图片的来源,它能给你提供更可用内存相匹配的精确尺寸的图片,载入一个缩小比例的版本到内存。
下面是要考虑的因素:
估算下图片完全载入所需要的内存
在保证你应用所需的其他内存的前提下,你愿意给这个图片分配多少内存
展示图片的目标ImageView或者是UI组件的尺寸
当前设备的屏幕大小和密度
比如:如果一个图片要展示在128x96像素的ImageView上,载入1024x768像素的图片到内存是不值当的。
为了告诉解码器生成图片的子副本,载入一个小版本到内存,在BitmapFactory.Options中把inSampleSize设置成true。
比如:一个图片的分辨率是2048x1536,如果用inSampleSize是4来解码,得到的图片大概是512x384。
把这个图片载入内存会占用0.75M而不是载入完整图片时候的12M(假设图片是ARGB_8888)。
下面是一个计算inSampleSize值的方法,返回值是基于目标宽度和高度的2的幂次方:
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image 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; } } return inSampleSize; }注意:结果是2的幂次方,这是因为解码器最终使用的值是最接近的2的幂次方,inSampleSize文档有说明。
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) { // First decode with inJustDecodeBounds=true to check dimensions final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(res, resId, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; return BitmapFactory.decodeResource(res, resId, options); }使用这个方法很简单就可以把任意大小的图片载入到100x100像素的ImageView,如下代码所示:
mImageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));你可以按照这种处理方式从不同的数据源来解码图片,只需要替换成相对应的BitmapFactory.decode*就可以了。