高效率地加载位图Loading Large Bitmaps Efficently——翻译自developer.andoid.com Training

来源:互联网 发布:linux 系统api 编辑:程序博客网 时间:2024/06/06 16:38

图像有各种各样的大小。很多时候图像都比我们需要的交互界面要打。例如系统图库中显示的图片,他们的分辨率要远远大于屏幕的分辨率。


你可以使用内存是有限的,你希望加载一个低分辨率的相片版本到内存中。低分辨率版本应该和显示他的ui组件相适应。一个高分辨率的图片在这是在视觉上不会有任何的提升,而仍然会占用宝贵的内存资源,并且产生多余的性能开销,源自于多余的频繁的缩放。


这节课向你展示怎样解码一个位图使之不超过每一个应用的内存限制,通过加载一个小版本的示例图到内存中来实现。


读位图的规格和类型

BitmapFactory类提供了多种从多种源解码的方式,比如(decodeByteArray(),decodeFile(),decodeResource())。选择对于你的数据源而言最合适的方法。这些方法试图按照格式化的位图进行空间分配,从而很容易产生内存溢出的异常。每一个解码方法都有以下附加标志,你可以通过使用BitmapFactory.Options类来制定解码的选项。通过设置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;
在加载图片分配内存之前判断图片的规格,这样可以避免java.lang.OutOfMemory异常。除非你身份确信你的图片源都是合理的尺寸,在你的可用的内存中可以合适地分配。

加载一个缩小的版本到内存

现在图片的规格已知了,这可以让我们用来判断是可以加载一个原图到内存还是加载一个缩小的版本。有下面几个方面需要考虑:
- 估计全部加载的话需要占用的内存。
- 在保留应用的其他部分的需要的情况下,你可以为加载图片支出的内存。
- 加载图片的imageView或者其他类型的组件的规格。
- 当前设备的屏幕大小和分辨率。

例如,如果你要在一个128*96的imageView中显示一个1024*768大小的图片,全部加载就是不值得的。可以通过设置inSampleSize为true来告诉解析器进行一个二次采样的解析,在BitmapFacotry.Options对象中。例如,一个分辨率为2048*1536的图像使用一个imSampleSize为4的参数进行解码,得到的大概就是512*384的图像。加载这个仅仅使用了0.75M的内存,而全图要使用12M的内存(假设图片的格式是ARGB_8888)。下面是一个基于图片的宽和高计算二的次方类型的规格变量sizevalue的方法。
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;
提示:这里我们之所以使用而的次方值是因为解码方法中会对数值进行舍入,使之为最接近的二的次方数,可以参见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的缩略图变的更加容易,就如同上面的代码展示的那样。


mImageView.setImageBitmap(    decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
你可以用类似的步骤来解码其他源的图片,只要用对应的方法取代BitmapFactory.decode*方法就可以了。

































0 0
原创粉丝点击