您的位置:首页 > 移动开发 > Android开发

Android大图加载方法

2013-07-10 21:32 302 查看
本文译自:http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

图片有各种形状和尺寸。在很多情况下,它们通常要大于显示图片用的用户界面(UI)。例如,系统的Gallery应用程序会显示Android设备的照相机所拍摄的照片,通常照片的分辨率要高于设备的屏幕密度。

由于内存的限制,你可能只想在内存中加载较低分辨率的图片版本。低分辨率版本应该跟显示它的UI组件尺寸相匹配。高分辨率的图片不会有益于显示,但是依然会消耗高贵的内存,并且由于缩放还会导致性能下降。

本文讲解如何用较小的采样版本来解码大位图,而不让其超过每个应用程序内存的限制。

读取位图的尺寸和类型

BitmapFactory类提供了几个解码方法(如decodeByteArray()、decodeFile()、decodeResource()等)来创建来自各种资源的位图(Bitmap)。基于图片数据源来选择最恰当的解码方法。这些方法尝试着给被创建的位图分配内存,内存很容易产生OutOfMemory异常。每种类型的解码方法都有一个附加的标识,这个标识会通过BitmapFactory.Options类让你指定解码选项。

inJustDecodeBounds属性设置为true,解码时会避免过度的内存分配,除了设置outWidthoutHeightoutMimeType属性设置以外的位图对象都会返回null。这种技术会允许你在构造(和分配内存)位图之前读取图片数据打的尺寸和类型。

BitmapFactory.Options options =newBitmapFactory.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异常,就要在解码之前检查位图的尺寸,除非你确信提供给你的图片数据源能够适合可用的内存。

把缩小的图片加载到内存中

获取图片的尺寸之后,就可以用它来判断是否可以把图片完整的加载到内存中,或者是降低采样率来加载图片。以下是要考虑的一些因素:

1. 估算把图片完整的加载到内存时所有使用的内存;

2. 除了图片的内存需求之外,应用程序的其他内存需求;

3. 显示图片的UI组件的尺寸;

4. 当前设备的屏幕尺寸和密度。

例如,把一个1024x768像素的图片完全加载到内存中,并在一个128x96像素的ImageView组件中,这种内存消耗是不值得的。

设置BitmapFactory.Options对象的inSampleSize属性,就可以告诉解码器降低采样率,把较小的分辨率的图片加载到内存中。例如,inSampleSize属性设置为4,那么分辨率为2048x1536的图片就可以解码为512x384像素的位图。这时所消耗的内存是0.75MB而不是12MB(假设位图是ARGB_8888形态)。以下是基于目标的宽度和高度来计算采样尺寸值的方法:

publicstaticintcalculateInSampleSize(
            BitmapFactory.Options options, int reqWidth, int reqHeight) {

    // Raw height and width ofimage

    final int height = options.outHeight;

    final int width = options.outWidth;

    intinSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        // Calculateratios 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);

        // Choosethe smallest ratio as inSampleSize value, this will guarantee

        // a finalimage with both dimensions larger than or equal to the

        // requestedheight and width.

        inSampleSize = heightRatio < widthRatio ?heightRatio : widthRatio;

    }

    return inSampleSize;

}

注意:inSampleSize值使用2的倍数会使解码器更快、更高效。但是,如果你只是打算在内存或硬盘上缓存调整后版本,那么通常采用最恰当的图片尺寸来解码,以便节省存储空间,这依然是值得的。

要使用这种方法,首先要把inJustDecodeBounds设置为true进行一次解码,然后再使用新的inSampleSize的值来再次解码,并把inJustDecodeBounds设置为false:

publicstaticBitmapdecodeSampledBitmapFromResource(Resources res,int resId,
        int reqWidth, int reqHeight) {

    // First decode withinJustDecodeBounds=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 withinSampleSize set

    options.inJustDecodeBounds = false;

    return BitmapFactory.decodeResource(res, resId, options);

这种方法使得把任意大尺寸的图片加载到一个显示100x100像素的小ImageView中来显示变得很容易。例如:

mImageView.setImageBitmap(
    decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));

你可以使用类似过程对来自其他类型资源的位图进行解码,只需用相应的BitmapFactory.decode*方法来代替就可以了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息