Android Bitmap那些事之如何优化内存

“安得广夏千万间,大庇天下寒士俱欢颜”——杜甫。

前言:在帝都住的朋友们都可能会遇到租房子困难的问题(土豪请无视),找房子真是力气活,还耗费时间,占用我宝贵的写博客时间,没办法,谁让咱没钱还想住的好点,努力努力挣钱!!!以上发点牢骚,现在进入正题。上一篇博客《Bitmap那些事之内存占用计算和加载注意事项》,写了Bitmap基础知识和使用Bitmap需要知道的注意事项,这一片博客我会写在Android应用中Bitmap的创建和加载。

1、BitmapFactory使用:

说到图片的加载就必须说BitmapFactory,看名字就知道他的作用了,就是一个生产Bitmap的工厂,下图是它的一些工厂方法:

从上图可以看到BitmapFactory可以使用存储Bitmap数据的数组,Bitmap的资源ID,Bitmap文件等做为数据源来创建Bitmap对象,具体情况看你程序中提供的数据源是哪一种。这些方法中对每一种数据源都提供了两个方法,这里需要注意一下BitmapFacotry.Options参数,它是BitmapFactory的内部类,有一些成员变量含义需要记一下,下面就来说说。

2、BitmapFacotry.Options的inJustDecodeBounds 参数使用:

为了节省内存,很多情况下原图片都要经过缩放处理,根据控件的尺寸来处理成对应尺寸的图片,这时使用BitmapFactory创建Bitmap,很多情况下都会使用下面的代码:

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;

注意上面中的options.inJustDecodeBounds =true的inJustDecodeBounds参数,为了避免我翻译的不准确我这里先贴出来google的原文: If set to true, the decoder will return null (no bitmap), but the out... fields will still be set, allowing the caller to query the bitmap without having to allocate the memory for its pixels。用我的话来说就是在decode的时候不给这个bitmap的像素区分配内存,除了这个区别Bitmap的其他信息你都能获取到。这样就有很大的意义,你既没有消耗内存又拿到了图片的信息,为你下一步图片处理提供帮助。

3、BitmapFacotry.Options的inSampleSize参数使用:

上一步你已经获取到图片的原始尺寸了,下一步就是要把原图缩放到你需要的大小,可以通过inSampleSize参数来设置,google原文的解释是:If set to a value > 1, requests the decoder to subsample the original image, returning a smaller image to save memory. The sample size is the number of pixels in either dimension that correspond to a single pixel in the decoded bitmap. For example, inSampleSize == 4 returns an image that is 1/4 the width/height of the original, and 1/16 the number of pixels. Any value <= 1 is treated the same as 1. Note: the decoder will try to fulfill this request, but the resulting bitmap may have different dimensions that precisely what has been requested. Also, powers of 2 are often faster/easier for the decoder to honor.(不管你看不看英文文档我还是要把google原文贴出来,我英文比较烂,翻译的不一定准确),大概意思就是说这个参数可以调节你在decode原图时所需要的内存,有点像采样率,会丢掉一些像素,值是大于1的数,为2的幂时更利于运算。举个例子:当 inSampleSize == 4 时会返回一个尺寸(长和宽)是原始尺寸1/4,像素是原来1/16的图片。这个值怎么计算呢?

public static int calculateInSampleSize( BitmapFactory.Options options,int reqWidth,int reqHeight){ // Raw height and width of image finalint height = options.outHeight; finalint width = options.outWidth; int inSampleSize =1; if(height > reqHeight || width > reqWidth){ finalint halfHeight = height /2; finalint 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; }

在decode的时候先设置options.inJustDecodeBounds =true,获取到图片参数后再设置为false,这就是decode时的技巧,下面就把完整代码贴出来,可以作为工具方法来使用:

public static Bitmap decodeSampledBitmapFromResource(Resources res,int resId, int reqWidth,int reqHeight){ // First decode with inJustDecodeBounds=true to check dimensions finalBitmapFactory.Options options =newBitmapFactory.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; returnBitmapFactory.decodeResource(res, resId, options); }

上面的方法来自于google官网,没必要进行修改,这就是程序员的拿来主义吧,关键在于要知道为什么这么写。下面是我自己写的一个方法可以直接拿来当工具用。

/** * 对图片进行压缩,主要是为了解决控件显示过大图片占用内存造成OOM问题,一般压缩后的图片大小应该和用来展示它的控件大小相近. * * @param context 上下文 * @param resId 图片资源Id * @param reqWidth 期望压缩的宽度 * @param reqHeight 期望压缩的高度 * @return 压缩后的图片 */ public static Bitmap compressBitmapFromResourse(Context context, int resId, int reqWidth, int reqHeight) { final BitmapFactory.Options options = new BitmapFactory.Options(); /* * 第一次解析时,inJustDecodeBounds设置为true, * 禁止为bitmap分配内存,虽然bitmap返回值为空,但可以获取图片大小 */ options.inJustDecodeBounds = true; BitmapFactory.decodeResource(context.getResources(), resId, options); final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int heightRatio = Math.round((float) height / (float) reqHeight); final int widthRatio = Math.round((float) width / (float) reqWidth); inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; } options.inSampleSize = inSampleSize; // 使用计算得到的inSampleSize值再次解析图片 options.inJustDecodeBounds = false; return BitmapFactory.decodeResource(context.getResources(), resId, options); }

原文发布于微信公众号 - 程序员互动联盟(coder_online)

原文发表时间:2015-04-20

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏10km的专栏

OpenBLAS:改进OpenBLASConfig.cmake生成方式,解除cmake脚本的路径依赖

问题描述 当我们用OpenBLAS提供的Makefile进行编译,并用make install PREFIX=/you/install/path,安装到指定的路...

3387
来自专栏everhad

[翻译]Bitmap的异步加载和缓存

内容概述 [翻译]开发文档:android Bitmap的高效使用 本文内容来自开发文档“Traning > Displaying Bitmaps Effic...

2425
来自专栏葡萄城控件技术团队

Spread for Windows Forms快速入门(6)---定义单元格的外观

在Spread中每个单元格都可以被看作一个独立的对象,开发人员不仅可以设置单元格的类型,而且可以为每个单元格设置不同的外观属性。 设置单元格的颜色 你可以为一个...

1789
来自专栏ml

Java之线程———GUI线程(包含打字游戏和计时器俩个GUI实列)

     当java程序包含图形用户界面(GUI)时,Java虚拟机在运行应用程序时会自动启动更多的线程,其中有两个重要的线程:AWT-EventQuecue ...

3766
来自专栏用户画像

Html 收银页面设计

1343
来自专栏郭霖

Android瀑布流照片墙实现,体验不规则排列的美感

传统界面的布局方式总是行列分明、坐落有序的,这种布局已是司空见惯,在不知不觉中大家都已经对它产生了审美疲劳。这个时候瀑布流布局的出现,就给人带来了耳目一新的感觉...

2335
来自专栏移动开发

FruitLoadView 一个自定义view可用来做加载view

Github地址:https://github.com/X-FAN/FruitLoadView 欢迎star

702
来自专栏ml

初学java之面板布局的控制

1 /* 2 * 联系网格的布控laytout 3 *以一个棋盘为列子吧! 4 */ 5 import javax.swing.*; 6 ...

3057
来自专栏Java帮帮-微信公众号-技术文章全总结

Java开发画板

Test类 public class Test { public static void main(String[] args){ ...

3625
来自专栏华仔的技术笔记

以太坊的数据结构

2824

扫码关注云+社区