android图片:高效加载大图

图片有各种大小和形状,很多时候我们要显示的图片的分辨率大小远大于手机屏幕的分辨率,这时候我们通常是先对图片做压缩再加载到内存显示,因为一方面原图占用太多内存,容易导致OOM,另一方面,只要压缩适当,压缩后的图片在手机上的显示效果和原图没太大差别,手机分辨率就这么多,你原图分辨率再高,显示在手机屏幕上,也超不过其最大分辨率,视觉上看起来效果一样,占用的内存却大大不一样。

 

BitmapFactory提供了对图片操作的一系列方法,下面是对图片压缩的一个写法。


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

开始时将inJustDecodeBounds属性设置为true,避免为图片分配内存,但是却可以读取图片的大小,再通过这个大小计算出压缩倍数inSampleSize,之后再将inJustDecodeBounds属性设置为false,读取压缩后的图片,并为其分配内存。下面看一下计算inSampleSize的具体实现。


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

这里有两个问题:

1、  为什么要先把高宽除以2.

2、  为什么每次都是inSampleSize*2,也就是为什么inSampleSize的值是2的幂。

 

         高宽除以2,是因为存在这么一种情况,原图高宽除以2之后,大小比要显示的高宽要小,这个时候如果inSampleSize*2的话,图片会有些失真。例如原图是100*100,而要显示的图的大小是80*80,如果设置inSampleSize为2,那么压缩后的图为50*50,50*50的图片显示在80*80的ImageView中,会有些失真,所以这个时候inSampleSize应该为1,将100*100的图片显示在80*80的ImageView中,就不会失真。

   

        inSampleSize的值是2的幂,是因为解码器使用基于2的幂值, inSampleSize的其他任何值将被四舍五入到最近的2的幂(Note: thedecoder uses a final value based on powers of 2, any other value will berounded down to the nearest power of 2.)。所以我们这里直接就把inSampleSize处理为2的幂值。

 

当然,计算inSampleSize的方法可以根据实际情况来设置,例如你就是要把图片压缩的占用内存更小,不考虑失真,那么完全可以把inSampleSize设置为一个更大的值。

 

根据上面的方法,假设想在100*100的ImageView中显示图片,就可以这么写了:


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



你可能感兴趣的:(android+java,android,图片,压缩,oom,内存)