Loading Large Bitmaps Efficiently-高效的加载大位图

来源:互联网 发布:协同过滤推荐算法java 编辑:程序博客网 时间:2024/04/30 09:05
     图片有各种形状和大小,在很多情况下,对于一个典型的应用程序用户界面来说它们都偏大了。例如系统相册展示的安卓设备相机拍摄的照片一般来说都比设备屏幕的像素密度高很多。
    由于你工作在有限的内存,最理想的情况是在内存中加载低分辨率的图片。低分辨率的图片只要匹配展示图片的UI组件的大小就行了。高分辨率的图片并不会给视觉带来更多益处,但是却占用了宝贵的内存,而且在滑动缩放的时候易引发性能问题。
    本次课程教你在内存中通过加载小的样本位图来解码大的位图,而不会超过每个应用程序的内存限制。

【读取位图尺寸和类型】
BitmapFactory类提供了一些解码方法 (decodeByteArray(), decodeFile(), decodeResource(), 等.) 从各种源来创建位图Bitmap。选择最合适的解码方法依赖于你的图片数据源。这些方法试图按照bitmap的构造方法分配内存,因此很容易导致OutOfMemory异常。每一种解码方法还有额外的通过 BitmapFactory.Options来指定解码选项的签名,在解码时设置inJustDecodeBounds属性为真可以避免分配内存,虽然返回的是空位图,但是图片的outWidth, outHeight 和outMimeType属性已经获得。这种技术可以让在创建位图(和内存分配)前获取位图的尺寸和类型。

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 内存溢出异常,在解码图片前要检查图片的尺寸,除非确信为您提供的是可预见尺寸的,占用内存合适的图像数据源。

【在内存中加载一个缩小版的图片】
现在图片的尺寸已经知道,可以用来在内存中加载全尺寸的图片或者加载缩小的子样本图片。这里有一些因素需要考虑:
*估计加载全尺寸内存使用情况
*对于加载此图片,你的应用程序能够给它分配的内存数量
*此图片装载的ImageView或者UI组件的尺寸
*当前设备的屏幕大小和密度
例如,把1024×768像素的图像载入到内存,如果它最终将在ImageView里显示一个128X96像素的缩略图,这是不值得的。
  告诉解码器加载一个缩小版的图片样本到内存,在 BitmapFactory.Options对象里设置 inSampleSize为真,例如一个分辨率为2048*1536的图片用inSampleSize为4解码,将会生成一个约512*384的图片。加载此图片到内存只会占用0.75MB而不是全尺寸的12MB(假设位图配置为ARGB_8888)。下面提供一个方法来计算一个图片样本的大小值,该值是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文档。
为了使用此方法,第一步将 inJustDecodeBounds设置为true,传递options参数,然后使用新的 inSampleSize值,并设置inJustDecodeBounds为false:

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);}
这种方法可以很简单的将任意大的位图以100*100像素的缩略图展现在的ImageView中,就像下面的代码

mImageView.setImageBitmap(    decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
你可以通过相似的方法处理从其他源来解码的位图,通过替换合适的BitmapFactory.decode* 解码方法。

翻译自:http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

0 0
原创粉丝点击