高效地加载大Bitmap

简介:

http://my.oschina.net/ryanhoo/blog/88242

译者:Ryan Hoo

来源:https://developer.android.com/develop/index.html

译者按: 在Google最新的文档中,提供了一系列含金量相当高的教程。因为种种原因而鲜为人知,真是可惜!Ryan将会细心整理,将之翻译成中文,希望对开发者有所帮助。

        本系列是Google关于展示大Bitmap(位图)的官方演示,可以有效的解决内存限制,更加有效的加载并显示图片,同时避免让人头疼的OOM(Out Of Memory)。

-------------------------------------------------------------------------------------

译文:

          图像可以有各种各样的形状和大小。在很多情况下,它们往往会比典型的应用UI界面所需要的更大。例如,系统的Gallery程序展示使用Android设备的摄像头拍摄的照片的分辨率往往要远高于设备的屏幕密度。  

        考虑到你所使用的内存有限,理想的情况是你只会想加载一个分辨率相对较低的图片到内存中来。低分辨率版本的图片与相应UI组件的尺寸应该是相匹配的。一张高分辨率的图片并不能带给你任何可见的好处,却要占据着宝贵的内存,以及间接导致由于动态缩放引起额外性能开销。  

        这节课将向你演示如何解码大图片,通过加载较小的图片采样以避免超出应用的内存限制。


读取Bitmap(位图)的尺寸和类型

        BitmapFactory提供了几种解码方式(decodeByteArray(), decodeFile(), decodeResource()等等),以便从多种资源中创建一个Bitmap(位图)对象。可以根据你的图片数据来源选择最合适的解码方式。这些方法视图为构造Bitmap对象分配内存,因此很容易导致OutOfMemory(OOM)异常。每一种解码方式都有额外的特征,你可以通过BitmapFactory.Options类类指定解码方法。在解码图片的时候设置inJustDecodeBounds属性为true,可以避免内存分配,返回的bitmap对象为null却可以设置outWidth, outHeight和outMimeType。这项技术允许你在创建Bitmap(并分配内存)之前读取图片的尺寸和类型。

1 BitmapFactory.Options options = new BitmapFactory.Options();
2 options.inJustDecodeBounds = true;
3 BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
4 int imageHeight = options.outHeight;
5 int imageWidth = options.outWidth;
6 String imageType = options.outMimeType;
        为了避免java.lang.OutOfMemeory异常,在解码图片之前就要检查图片的尺寸,除非你十分确信图片资源的尺寸是可预见的并且有着充裕的可用内存。  

将缩小版的图片加载到内存中  

        现在图片的尺寸已经知道了,这些信息可以用来决定是将一个完整尺寸的图片加载到内存中,还是应该用一个图片的子样本来取代它。这里有一些可供考虑的因素:  
  • 估计加载全尺寸的图片所要消耗的内存
  • 在考虑应用中其他内存需求的情况下,你愿意给加载这个图片分配的内存空间。
  • 准备加载该图像的目标ImageView或者UI组件的尺寸
  • 当前设备的屏幕的尺寸和密度

        例如,如果最终只是要在ImageView中显示一张128*96px大小的缩略图,直接加载1024*768px的图片是非常不值得的。

        为了告诉解码器如何对图像进行采样,加载更小版本的图片,需要在BitmapFactory.Options对象中将inSampleSize设置为true。例如,一张分辨率为2048*1536px的图像使用inSampleSize值为4的设置来解码,产生的Bitmap大小约为512*384px。相较于完整图片占用12M的内存,这种方式只需0.75M内存(假设Bitmap配置为ARGB_8888)。这里有一个方法用来计算基于目标高宽的sample size的值:

01 public static int calculateInSampleSize(
02             BitmapFactory.Options options, int reqWidth, int reqHeight) {
03     // Raw height and width of image
04     final int height = options.outHeight;
05     final int width = options.outWidth;
06     int inSampleSize = 1;
07  
08     if (height > reqHeight || width > reqWidth) {
09         if (width > height) {
10             inSampleSize = Math.round((float)height / (float)reqHeight);
11         else {
12             inSampleSize = Math.round((float)width / (float)reqWidth);
13         }
14     }
15     return inSampleSize;
16 }

        提示:使用2的次幂来设置inSampleSize值可以使解码器执行地更加迅速、更加高效。但是,如果你想在内存或者硬盘上缓存一个调整过大小的图片,通常还是解码到合适的图片尺寸更加节省空间。

        要使用这个方法,首先要使用inJustDecodeBoundstrue来解码尺寸信息,将options传递过去使用新的inSampleSize值再次解码并且要将inJustDecodeBounds值设置为false

01 public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
02         int reqWidth, int reqHeight) {
03  
04     // First decode with inJustDecodeBounds=true to check dimensions
05     final BitmapFactory.Options options = new BitmapFactory.Options();
06     options.inJustDecodeBounds = true;
07     BitmapFactory.decodeResource(res, resId, options);
08  
09     // Calculate inSampleSize
10     options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
11  
12     // Decode bitmap with inSampleSize set
13     options.inJustDecodeBounds = false;
14     return BitmapFactory.decodeResource(res, resId, options);
15 }
        这个方法使得加载任意大小的Bitmap到展示100*100px缩略图的ImageView中更加简单,如下代码所示:  
1 mImageView.setImageBitmap(
2     decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100100));
        你可以根据需要,按照类似的解码过程,采用适当的BitmapFactory.decode*方法从其他资源中解码Bitmap。
目录
相关文章
|
存储 缓存 监控
内存优化 | Bitmap优化
在内存优化中,优化 Bitmap 占用的内存效果最为明显,在 Android 里面,大部分 OOM,都是 bitmap 占用资源过大导致的,那么问题来了 如何防止 bitmap 占用资源过大导致 OOM?Android 系统何时会发生 OOM?怎样搭建线上线下一体化内存监控体系?Drump 文件过大,我们线上如何查看?线下监控那些工具你会用吗?关于 Native 层的内存泄漏该如何解决?图片监控你做过哪些努力?内存抖动为什么会引起 OOM?内存监控里面采集方式有哪些? 看完本文,希望可以以本文为索引,然后依次排雷解决上述问题,这样你也是这个领域的专家了
439 0
内存优化 | Bitmap优化
|
编解码 Android开发
性能优化:Android中Bitmap内存大小优化的几种常见方式
性能优化:Android中Bitmap内存大小优化的几种常见方式
Bitmap高效加载
我们在编程中,如果要插入一张图片,大部分直接使用ImageView直接加载,但在实际编程当中,有时候图片的原始尺寸并不符合ImageView。 使用BitmapFactory类中的四个方法:decodeFile,decodeResource,decodeStream,decodeByteArray(文件,资源,IO流,字节数组)中加载Bitmap对象,可以使用InSampleSize采样率来缩小图片,还可以缩小图片内存大小,一定程度避免OOM。
|
缓存 监控 安全
【Android 内存优化】Bitmap 内存缓存 ( Bitmap 内存复用 | 弱引用 | 引用队列 | 针对不同 Android 版本开发不同的 Bitmap 复用策略 | 工具类代码 )
【Android 内存优化】Bitmap 内存缓存 ( Bitmap 内存复用 | 弱引用 | 引用队列 | 针对不同 Android 版本开发不同的 Bitmap 复用策略 | 工具类代码 )
325 0
|
API Android开发
【Android 内存优化】Bitmap 长图加载 ( BitmapRegionDecoder 简介 | BitmapRegionDecoder 使用流程 | 区域解码加载示例 )
【Android 内存优化】Bitmap 长图加载 ( BitmapRegionDecoder 简介 | BitmapRegionDecoder 使用流程 | 区域解码加载示例 )
272 0
【Android 内存优化】Bitmap 长图加载 ( BitmapRegionDecoder 简介 | BitmapRegionDecoder 使用流程 | 区域解码加载示例 )
|
存储 编解码 Android开发
【Android 内存优化】Bitmap 内存占用计算 ( Bitmap 图片内存占用分析 | Bitmap 内存占用计算 | Bitmap 不同像素密度间的转换 )
【Android 内存优化】Bitmap 内存占用计算 ( Bitmap 图片内存占用分析 | Bitmap 内存占用计算 | Bitmap 不同像素密度间的转换 )
165 0
|
存储 缓存 Android开发
【Android 内存优化】Bitmap 硬盘缓存 ( Google 官方 Bitmap 示例 | DiskLruCache 开源库 | 代码示例 )(一)
【Android 内存优化】Bitmap 硬盘缓存 ( Google 官方 Bitmap 示例 | DiskLruCache 开源库 | 代码示例 )(一)
262 0
【Android 内存优化】Bitmap 硬盘缓存 ( Google 官方 Bitmap 示例 | DiskLruCache 开源库 | 代码示例 )(一)
|
存储 缓存 API
【Android 内存优化】Bitmap 硬盘缓存 ( Google 官方 Bitmap 示例 | DiskLruCache 开源库 | 代码示例 )(二)
【Android 内存优化】Bitmap 硬盘缓存 ( Google 官方 Bitmap 示例 | DiskLruCache 开源库 | 代码示例 )(二)
159 0
|
存储 Java 数据处理
【Android 内存优化】Android 工程中使用 libjpeg-turbo 压缩图片 ( JNI 传递 Bitmap | 获取位图信息 | 获取图像数据 | 图像数据过滤 | 释放资源 )
【Android 内存优化】Android 工程中使用 libjpeg-turbo 压缩图片 ( JNI 传递 Bitmap | 获取位图信息 | 获取图像数据 | 图像数据过滤 | 释放资源 )
313 0
|
缓存 Java API

热门文章

最新文章