Android Developers:高效的加载大的位图

图片以各种各样的形式展现。在许多情况下,它比一个典型应用程序用户界面(UI)的要求更大。例如,系统的Gallery应用程序显示使用Android设备的照相机拍摄的照片,它是典型的比你设备屏幕的密度大很多。

考虑到你在内存限制的条件下工作, 理想的情况下,你仅仅需要加载一个低分辨率的版本到内存中。这低分辨率的版本应该和显示它的UI组件的大小符合。一个高分辨率的图片不会有任何可见的好处,但是一直消耗宝贵的内存和由于额外的缩放产生的附加的性能损失。
这节课程将引导你,通过加载一个更小的子样品版本到内存中,在不超出每个程序内存显示的情况下编码大位图。

获取位图的尺寸和类型

BitmapFactory类提供了几个编码方法(decodeByteArray(),decodeFile(),decodeResource()等)用于从各种源创建一个位图。在你的图片数据源的基础上选择最合适的编码方式。这些方法为了构造位图试图分配内存,因此能很容易产生OutOfMemory异常。每一种编码方式都有额外的特性,你可以通过BitmapFactory.Option类指定编码选项。设置inJustDecodeBounds属性为true,在编码的时候避免内存分配,位图对象返回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异常,在编码之前检查位图的尺寸,除非你绝对的确信提供给你的图片的数据大小在可用的内存中充分的合适。

向内存中加载一个缩小版本

现在图片的尺寸已经已知,它用来决定是向内存中加载整张图片还是加载一个子版本代替。下面有几个你需要考虑的因素:
    • 估算加载整张图片的内存消耗。
    • 根据应用程序其他的内存需求,你愿意为加载这张图片所分配的内存。
    • 加载图片的ImageVeiw或UI控件的尺寸。
    • 当前设备的屏幕大小和尺寸。
例如,如果为了在一个ImageView中128*96像素的地方显示,而向内存中加载一张1024*768的图片,这是不值得的。
        告诉你的编码器对图片进行采样,向内存中加载一个小版本的图片,在BitmapFactory.Option对象中设置inSampleSize属性为true。例如,一张使用inSampleSize为4属性编码的分辨率为2048*1536的图片,最终产生一张大约512*384的位图。向内存中加载它使用0.75MB而不是加载整张图片(假定使用ARGB_8888编码位图)的12MB。下面的方法是一个基于目标的宽和高计算抽样的大小:
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设置为true,获取options。然后将inJustDecodeBounds设置为false,并传入options和新的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);
}
这种方法使在100*100像素的ImageView缩略图中加载任意大小的图片变得很容易,如下示例代码所示:
mImageView.setImageBitmap(
    decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));

你可以使用相似的流程从其它的源中编码位图,根据需要通过替换相应的BitmapFactory.decode.*方法即可。


文档目录:Developers/Training/Advanced Tranining/Displaying Bitmaps Efficiently/Loading Large Bitmaps Efficiently

新技术,新未来!欢迎大家关注“1024工场”微信服务号,时刻关注我们的最新的技术讯息!(甭客气!尽情的扫描或者长按!)

     
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值