Android教程进阶:有效的处理较大的位图

时间:2013-03-19 09:17来源:eoeAndroid 作者:adminjet 点击:
图像有各种形状和大小。在许多情况下,他们往往比一个典型应用程序的用户界面(UI)所需要的资源更大。例如,系统的Gallery程序展示使用Android设备照相机所拍摄的照片通常要比你的设备的屏幕密度更高的分辨率下显示。

 

既然你所使用的内存有限,理想状况下你只想在内存中加载一个低版本的方案。低版本的方案应该匹配显示它的UI组件的大小。一个更高的解决方案不提供任何可见的好处,但是仍然占用以前的内存,由于额外的缩放会导致额外的性能开销。

 

这节课将引导你在不超过内存限制的情况下通过解码大位图,在内存中加载一个较小的位图子样本。

 

BitmapFactory类提供了集中解码的方法(decodeByteArray(),decodeFile(),decodeResource(),等等)从多种资源中来创建一个位图。选择最合适的解码方法基于你的图像数据资源。这些方法试图情去分配内存来构造位图,因此很容易导致OutOfMemory异常。每种类型的解码方法都有额外的特征可以让你通过BitMapFactory.Options类指定特定解码方法。当解码时避免内存分配可以设置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异常,在解码位图之前请检查它的维度,除非你十分确定资源提供给你的可预见的图像数据正好满足你的内存。 现在的图像尺寸都是已知的,他们可以被用来决定是否应该加载到存储器或者是否一个子样本的版本被加载。以下是一些值得考虑的因素:

 

    • 估计加载完整图像所需要的内存;
    • 你承诺加载这个图片所需空间带给你的程序的其他内存需求;
    • 准备加载图像的目标ImageView或UI组建尺寸;
    • 当前设备的屏幕尺寸和密度;
例如,如果1024* 768像素的图像最终被缩略地显示在一个128* 96像素的ImageView中,就不值得加载到内存中去。

 

告诉解码器去子样本化图像,加载一个更小的版本到内存中,在你的BitmapFactory.Option对象中设置inSampleSize为true。例如,将一个分辨率为2048* 1536的图像解码为4个子版本大小为大约512* 384的位图。加载这个到内存中仅使用0.75MB,而不是完整的12MB大小的图像(假设使用ARGB_8888位图的配置)。这里有一个方法在目标的宽度和高度的基础上来计算一个样本的大小。

  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;

  }

NOTE:使用2的幂数设置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);

  }


这种方法可以很容易地加载任意大小的位图到一个ImageView显示一个100x100像素的缩略图,如下面的示例代码所示:
  mImageView.setImageBitmap(

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

你可以按照类似的过程,用适当的BitmapFactory.decode* 中的方法去解码一个从其他资源得到的位图。

 

分享到:

凌阳教育培训【凌阳科技旗下教育品牌】——专业的培训机构,全国唯一“按班公布学员就业去向”的诚信机构

关注我们:

全国免费咨询电话:156-0117-5697或010-62981113(转2824) 服务监督电话:010-62981113-2800

京ICP备09010168号  京公网安备11010802010586号

北京安卓培训中心:海淀区上地信息产业基地中黎科技园1号楼3层A段

Copyright © 2017 SunplusEdu Inc. All Rights Reserved