高效的加载大图片(二)

原文地址:http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

图片有各种形状和大小 ,大多数情况他们都比界面所需要的来的大。例如,系统的Gallery应用展示照片通过设备的摄像头获取的分辨率比屏幕的分辨率要高许多。

由于缓存的限制,理论上只要加载低分辨率版本的到缓存中。低分辨率版本需要适配组件的展示大小。一个更高分辨率版本不会带来更多好处,反而要占用更多的内存,还会在产生而外的开销。

这节课将介绍在解析大图片时,通过加载一个更小的样品版本到缓存中来解决应用的缓存限制。

读取图片的大小和类型

BitmapFactory类提供了一些解码方法(decodeByteArray(),decodeFile(),decodeResource())通过各种资源来创建一个图片。基于图片数据资源选择合适的加密方法。这些方法会试图为图片分配内存,因此会很容易导致内容溢出异常。每一种解码方法都可以通过BitmapFactory.class类设置指定的配置。 设置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;

在解码图片时要确认他的大小,除非你确认图片资源适合可用的资源。

加载一个缩小的版本到缓存中

现在知道了图片的大小,可以通过这个来决定是否加载完整的图片或者是用他缩小的版本来替代。这里有一些需要考虑的因素:

1、预估加载完整的图片到内存中需要占用的内存。

2、能够给图片提供的内存数量

3、要加载图片的组件的大小

4、当前设备的大小和分辨率

例如,加载一个1024x768像素的图片到缓存用于一个128x96的ImageView组件展示,这是不值得的。

要让解码器加载一个低版本的图片样本到内存中,要设置BitmapFactory.Options属性inSampleSize为true。例如,一个图片的分辨率为2048x1536,解码时设置inSampleSize为4就会创造出一个近似512x384的图片。这样加载到缓存只会占用0.75MB而不是完整图片的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) {

        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:

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);
}

使用这个方法可以很容易的加载一个大的图片到一个100x100像素展示的ImageView控件,就像下面代码展示的一样:

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

你也可以使用BitmapFactory.decode*的其他方法,利用相似的流程来加载资源。



你可能感兴趣的:(高效的加载大图片(二))