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

Loading Large Bitmaps Efficiently

原文链接:http://developer.android.com/training/displaying-bitmaps/load-bitmap.html#load-bitmap

Read Bitmap Dimensions and Type

BitmapFactory 类提供了一系列的方法用于创建各种来源的位图(Bitmap),例如:decodeByteArray(),decodeFile(),decodeResource(),等等。我们可以根据图像数据的来源选择最合适的方法。这些方法会尝试给构造的位图分配内存,因此容易导致内存不足(OutOfMemory Exception)。每种类型的解码方法,我们都能通过类BitmapFactory.Options指定解码选项。在解码时将inJustDecodeBounds属性设置为 true 可以避免内存分配,解码方法返回的 bitmap 对象是null,但会设置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 异常,在解码图片之前我们需要知道图片的尺寸,除非你绝对信任数据源可以提供尺寸可预测的图片以恰好适配可用的内存。

Load a Scaled Down Version into Memory

现在,图片的尺寸已经知道了,依据它们,我们可以决定是加载完整的图像到内存里,还是加载一个二次取样的图像。下面是需要考虑的因素:

  • 预估加载完整图像需要的内存占用。
  • 你愿意为加载这个图像使用的内存大小。
  • 用于显示此图像的 ImageView 或 UI 控件的尺寸。
  • 屏幕尺寸和当前设备的分辨率。

举个例子来说,将一个1024x768像素的图片加载到内存中以显示在128x96像素大小的缩略图ImageView中是不值得的。

我们通过设置 BitmapFactory.Options 对象的属性 inSampleSize 为 true 来通知解码器对图像进行二次取样以加载更小版本的图像到内存中。例如,分辨率为2048x1536的图片依据 inSampleSize=4 进行解码会得到分辨率大约为512x384的位图,这样只需占用0.75MB的内存而不是完整图像所需要的12MB。下面的方法可用于计算样本尺寸的值,这个值是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;
}

下面的方法展示了压缩图片的完整过程,首先设置 inJustDecodeBounds 为 true 进行解码获取原始图片的尺寸,然后计算获得 inSampleSize,最后设置 inJustDecodeBounds 为false,并使用新的 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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值