有效地加载大位图文件-Loading Large Bitmaps Efficiently

图像有各种不同的形状和大小。在许多情况下,他们往往比一个典型应用程序的用户界面(UI)所需要的资源更大。例如,系统的Gallery程序展示使用Android设备的照相机所拍摄的照片通常要比你的设备的屏幕密度的分辨率更高。
既然你所使用的内存有限,理想状况下你只想在内存中加载一个低分辨率的版本。低分辨率的方案应该匹配显示它的UI组件的大小。一个更高分辨率的图片不提供任何可见的好处,但是由于额外的缩放会导致额外的性能开销,仍然占用缩放之前的内存,。
这节课将引导你在不超过内存限制的情况下通过解码大型位图,在内存中加载一个较小的位图子样本。
读取一个位图的尺寸和类型-Read Bitmap Dimensions and Type

为了从多种资源来创建一个位图,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异常,在解码位图之前请检查它的尺寸,除非你十分确定资源提供给你的可预见的图像数据正好满足你的内存。
加载一个缩小版本到内存中(Load a Scaled Down Version into Memory)

现在的图像尺寸都是已知的,他们可以被用来决定是否应该加载完整的图片到内存或者是否用一个缩小的版本去代替加载。以下是一些值得考虑的因素:
估计加载完整图像所需要的内存;
你承诺加载这个图片所需空间带给你的程序的其他内存需求;
准备加载图像的目标ImageView或UI组件尺寸;
当前设备的屏幕尺寸和密度;
例如,如果1024*768像素的图像最终被缩略地显示在一个128*96像素的ImageView中,就不值得加载到内存中去。
告诉解码器去重新采样这个图像,加载一个更小的版本到内存中,在你的BitmapFactory.Option对象中设置inSampleSize为true。例如,将一个分辨率为2048*1536的图像用 inSampleSize值为4去编码将产生一个大小为大约512*384的位图。加载这个到内存中仅使用0.75MB,而不是完整的12MB大小的图像(假设使用ARGB_8888位图的配置)。这里有一个方法在目标的宽度和高度的基础上来计算一个SampleSize的值。

  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*中的方法去解码一个从其他资源得到的位图

Loading Large Bitmaps Efficiently的更多相关文章

  1. Displaying Bitmaps Efficiently 显示图片相关

    http://developer.android.com/training/displaying-bitmaps/index.html .手机内存资源有限 .Bitmap占用的内存大 .App有时需要 ...

  2. trying to draw too large(106,975,232 bytes) bitmap.

    Loading Large Bitmaps Efficiently This lesson teaches you to Read Bitmap Dimensions and Type Load a ...

  3. [译]Android调整图像大小的一些方法

    翻译自 某大神在Stack Overflow里的自问自答 (一般我们将Bitmap翻译为位图,但为了更好理解,在本文中我将它翻译成图像): 我们在开发的时候,经常需要从服务器中加载图像到客户端中,但有 ...

  4. [原] Android持续优化 - 提高流畅度

    一.形象的感官一下流畅度概念 1. 这是官方给出的概念:Android流畅运行,需要运行60帧/秒, 则需要每帧的处理时间不超过16ms. 2. 每秒帧数,实际上就是指动画或视频每秒放映的画面数.因此 ...

  5. 学习笔记 - 深究Bitmap压缩避免OOM的核心inSampleSize的最佳取值

    /** * 测试代码,通过在SDCard根目录放置几种不同大小的图片, 来自动测试压缩方式是否有效同时看是否会内存不够. * * @since * By:AsionTang * At:2014年3月2 ...

  6. android 高效显示Bitmap - 开发文档翻译

    由于本人英文能力实在有限,不足之初敬请谅解 本博客只要没有注明“转”,那么均为原创,转贴请注明本博客链接链接 Displaying Bitmaps Efficiently 高效显示Bitmap Lea ...

  7. Android Training

    Building Apps with Content Sharing Simple Data --> Intent && ActionProvider 介绍如何让应用程序共享简单 ...

  8. Android训练课程(Android Training) - 高效的显示图片

    高效的显示图片(Displaying BitmapsEfficiently) 了解如何使用通用的技术来处理和读取位图对象,让您的用户界面(UI)组件是可响应的,并避免超过你的应用程序内存限制的方式.如 ...

  9. 【Android】自己定义圆形ImageView(圆形头像 可指定大小)

    近期在仿手Q的UI,这里面常常要用到的就是圆形头像,看到 在android中画圆形图片的几种办法 这篇文章,了解了制作这样的头像的原理.只是里面提供的方法另一个不足的地方就是不能依据实际需求改变图片的 ...

随机推荐

  1. sql server 纵横表的转换

    在平常的工作中或者面试中,我们可能有遇到过数据库的纵横表的转换问题.今天我们就来讨论下. 1.创建表 首先我们来创建一张表. sql语句: --1. 创建数据表 if OBJECT_ID('Score ...

  2. 将变参格式化到一个string对象中

    该小程序演示了变参的用法.它的功能是,仿照sprintf,将变参内容保存到string中. /* 功能说明: 仿照sprintf,将字符串格式化到一个string对象中. 实现方式: 该例子主要是用来 ...

  3. HDU4940 Destroy Transportation system(有上下界的最大流)

    Problem Description Tom is a commander, his task is destroying his enemy’s transportation system. Le ...

  4. C#进阶之路(五):Linq初识

    关于LINQ的文章,网上有很多,所以这篇文章我主要是总结下我自己的学习心得. 首先需要先了解的相关技术 1.隐式类型.匿名类型.对象初始化器 1)隐式类型,使用var关键字创建,C#编译器会根据用于初 ...

  5. java shell排序

    原理图: package suanfa; public class shellInsert { public void shellInsert1(double [] sorted,int inc){ ...

  6. 一次调用cloudera的的API和JSON想到的

    JSON的null字段 在我的项目中修改了YARN的资源池,到cloudera中就报错,查询还不报错,但是修改的时候,就报错,大致意思就是信息有异常,“包含了尖括号. 因为通过API+json交互,我 ...

  7. 流畅的python之序列

    python对开发者友好的根源在于:1.序列的泛型操作2.内置的元组和映身类型3.用缩进来架构的源码4.无需变量声明的强类型 序列数据共用的一套丰富的操作:迭代.切片.排序和拼接.内置序列类型:1.容 ...

  8. IPv4 forwarding is disabled. Networking will not work.

    centos 7 docker 启动了一个web服务 但是启动时 报 WARNING: IPv4 forwarding is disabled. Networking will not work. 网 ...

  9. [转载]Linux内核list_head学习(二)

    前一篇文章讨论了list_head 结构的基本结构和实现原理,本文主要介绍一下实例代码. 自己如果想在应用程序中使用list_head 的相应操作(当然应该没人使用了,C++ STL提供了list 用 ...

  10. SQLite连接C#笔记

    不得不吐槽,实在是太坑了.以下几点一定要注意: 要下载两个东西,都要上官网.一个是SQLite for Windows,一个是System.Data.SQLite. 下载下来的DLL里面有个test, ...