创建带有动画的APP 之 高效的显示位图:高效的载入大的位图

图片有不同的形状和像素。在很多情况下,都远远大于程序要求的标准大小。比方说,图库应用展示的相机拍照的图片,相机的解析率一般都比你的屏幕密度要高。

假定你的APP工作在有限内存的环境下,理想状态中你只是想载入一张低分辨率的图片,这张低分辨率的图片的尺寸要和将要显示它的控件相一致。一个高分辨率的图片,除了提供了高质量的可见度,而且还占用了珍贵的内存,而且额外的动态宽展也导致了高的性能消耗。

这一节里面就讲述一下如何在不超过每个APP内存限制的情况下,通过解析大的位图,得到一个小的版本,载入到内存中。

读取位图的大小和类型

BitmapFactory 类提供了一些解析bitmap的方法(decodeByteArray(), decodeFile(),decodeResource()等等)利用各种资源来创建一个Bitmap.选择哪种最合适的方法要根据的bitmap类型来决定。这些方法会分配一块内存来创建的bitmap,所以很容易导致内存溢出的问题。每一个方法都有一个额外的签名,这个可以让你通过BitmapFactory.Options来指定解析操作。设置inJustDecodeBounds属性为true,来避免内存的分配,会返回一个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之前先判断它的分辨率,除非你很确定在有限的内存下,你知道这个图像的资源可以提供合适的大小的图片。

载入缩放的图片到内存

现在知道图像的分辨率了,你就可以决定完全载入这个完成的图像还是说载入它的缩放的版本。下面是一些考虑的因素:

  • 估算要载入整个图像需要的内存
  • 考虑你的APP里面其他地方的需要的内存之外,你可以用来解码图像的内存数量
  • ImageView的分辨率或者说图像要载入的部件的分辨率
  • 当前设备的屏幕尺寸和密度

比方说,如果我们只想在128*96大小的ImageView里面显示一个图像,那就没有必要载入一个1024x768像素的图像。

要告诉解码器去创建一个图像的副样本版本载入到内存, BitmapFactory.Options里面的inSampleSize设置为true.例如,一个分辨率为2048x1536的图像,解码的时候我们把inSampleSize位置为4,那么出来的图片的副样本就是512x384分辨率的位图。载入这个副本到内存仅仅需要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) {

        // Calculate ratios of height and width to requested height and width
        final int heightRatio = Math.round((float) height / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);

        // Choose the smallest ratio as inSampleSize value, this will guarantee
        // a final image with both dimensions larger than or equal to the
        // requested height and width.
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    }

    return inSampleSize;
}


注意:让2为inSampleSize的值的时候,解码会更新快速和高效。然而,如果你想缓存这个改变大小后的图像到内存或者磁盘,那么选用更加合适的分辨率来解码这个图像是值得的。

用这个方法解码的第一步是设置inJustDecodeBounds为true,传递这个参数,然后再使用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* 方法。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值