高效显示Bitmap之高效加载较大的 Bitmaps

本文介绍如何通过调整图片采样率防止Android应用内存溢出。通过使用BitmapFactory.Options的inJustDecodeBounds属性读取图片尺寸,并计算合适的inSampleSize值以加载适当大小的图片。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

图片来源多种多样,多数情况下往往比要求的要大。例如,系统应用程序显示照片画廊通常使用Android设备的相机分辨率远高于你的设备的屏幕密度。

鉴于您在使用有限内存,理想情况下你需要加载一个低分辨率版本在内存中。低分辨率图片应该匹配显示它的UI组件大小。高分辨率图片不提供任何可见的好处,但是占据着宝贵的内存资源并且在动态缩放时带来额外的开销。

本节课教你解码大位图不超过每个应用程序内存限制通过加载一个更小的子样本版本图片在内存中。

Read Bitmap Dimensions and Type

 BitmapFactory类提供多种解码方法decodeByteArray()decodeFile(),decodeResource(), etc 从不同资源来创建一个位图。根据你的图片资源选择一个合适的解码方法。这些方法为构造的位图分配内存,因此会很容易发生OutOfMemory 异常.每种类型的解码方法有额外的签名,让你通过BitmapFactory指定解码选项。设置inJustDecodeBounds属性为true,在decoder时不会加载bitmap到内存,只会设置outWidthoutHeight 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;
为了避免内存溢出,在解码Bitmap之前检查其尺寸。

Load a Scaled Down Version into Memory

既然图片尺寸都知道了,可以决定是否需要原大图到内存还是加载一个子样本。以下是应该考虑的因素:

.估计要加载的图片内存大小

.你愿意承诺的内存加载图片给其他应用程序的内存需求。

.加载图片的目标ImageView或者UI组件的尺寸

.当前设备的屏幕大小和密度

例如,它不值得加载一个1024*768的图片到内存中而最终被显示在128*96像素ImageView中。

BitmapFactory.Options 中设置inSampleSize为ture来告诉子样品图像的解码器,加载一个低版本到内存中。例如,一个2048*1536的图片通过值为4的inSampleSize解码为512*384的位图。然后加载内存只会用0.75MB而不是原图的12MB(假如位图用 ARGB_8888).下面是一个基于目标宽和高来计算出缩放比例的方法:

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) {
        if (width > height) {
            inSampleSize = Math.round((float)height / (float)reqHeight);
        } else {
            inSampleSize = Math.round((float)width / (float)reqWidth);
        }
    }
    return inSampleSize;
}
标记:用2的方幂的inSampleSize 是更快、更有效的解码方式。然而,如果你计划缓存大小版本在内存或磁盘上,通常解码最合适的图片尺寸节省空间也是非常值得的。

用这个方法之前, inJustDecodeBounds设置为ture,用新的 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));
未完待续。。。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值