APP性能优化系列:内存优化-bitmap详解
Posted 安诺爱成长
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了APP性能优化系列:内存优化-bitmap详解相关的知识,希望对你有一定的参考价值。
在android应用开发中,我们经常需要跟图片打交道,而图片一个很麻烦的问题是占用内存非常大,经常导致OOM,了解Bitmap相关信息,不同sdk版本中Android图片处理的变化,以及一些优化处理的方式对我们平时开发中对图片的会非常有帮助。
在开始本节的内容之前我们.先来区分几个名词的概念:
Drawable:通用的图形对象,用于装载常用格式的图像,既可以是PNG,JPG这样的图像, 也是前面学的那13种Drawable类型的可视化对象!我们可以理解成一个用来放画的——画框!
Bitmap(位图):我们可以把他看作一个画架,我们先把画放到上面,然后我们可以 进行一些处理,比如获取图像文件信息,做旋转切割,放大缩小等操作!
Canvas(画布):如其名,画布,我们可以在上面作画(绘制),你既可以用Paint(画笔), 来画各种形状或者写字,又可以用Path(路径)来绘制多个点,然后连接成各种图形!
Matrix(矩阵):用于图形特效处理的,颜色矩阵(ColorMatrix),还有使用Matrix进行图像的平移,缩放,旋转,倾斜等!
一.bitmap相关api
了解Bitmap,BitmapFactory,BitmapFacotry.Options
1.Bitmap
bitmap常见方法:
普通方法
public boolean compress (Bitmap.CompressFormat format, int quality, OutputStream stream) 将位图的压缩到指定的OutputStream,可以理解成将Bitmap保存到文件中! format:格式,PNG,JPG等; quality:压缩质量,0-100,0表示最低画质压缩,100最大质量(PNG无损,会忽略品质设定) stream:输出流 返回值代表是否成功压缩到指定流!
void recycle():回收位图占用的内存空间,把位图标记为Dead
boolean isRecycled():判断位图内存是否已释放
int getWidth():获取位图的宽度
int getHeight():获取位图的高度
boolean isMutable():图片是否可修改
int getScaledWidth(Canvas canvas):获取指定密度转换后的图像的宽度
int getScaledHeight(Canvas canvas):获取指定密度转换后的图像的高度
静态方法:
Bitmap createBitmap(Bitmap src):以src为原图生成不可变得新图像
Bitmap createScaledBitmap(Bitmap src, int dstWidth,int dstHeight, boolean filter):以src为原图,创建新的图像,指定新图像的高宽以及是否变。
Bitmap createBitmap(int width, int height, Config config):创建指定格式、大小的位图
Bitmap createBitmap(Bitmap source, int x, int y, int width, int height)以source为原图,创建新的图片,指定起始坐标以及新图像的高宽。
public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)
2.BitmapFactory
Bitmap的构造方法是私有的,外面不能实例化,只能通过JNI实例化! 当然,肯定也会给我们提供一个接口给我们来创建Bitmap的,而这个接口类就是:BitmapFactory! 来来来,打开BitmapFactory类,我们点下左边的Structure可以看到BitmapFactory给我们 提供了这些方法,大部分都是decodeXxx,通过各种形式来创建Bitmap的!
3.BitmapFacotry.Options
接着我们又发现了,每一种方法,都会有一个Options类型的参数,点进去看看: 于是乎我们发现了这货是一个静态内部类:BitmapFacotry.Options! 而他是用来设置decode时的选项的!
我们对这里的某些参数的值进行设置,比如inJustDecodeBounds设置为true避免OOM(内存溢出).
常见的设置:
boolean inJustDecodeBounds——如果设置为true,不获取图片,不分配内存,但会返回图片的高宽度信息。
int inSampleSize——图片缩放的倍数。如果设为4,则宽和高都为原来的1/4,则图是原来的1/16。
int outWidth——获取图片的宽度值
int outHeight——获取图片的高度值
int inDensity——用于位图的像素压缩比
int inTargetDensity——用于目标位图的像素压缩比(要生成的位图)
boolean inScaled——设置为true时进行图片压缩,从inDensity到inTargetDensity。
二.bitmap占用的内存大小如何计算
结论:
一张 ARGB_8888 的 Bitmap 占用内存的计算公式:
bitmapInRam = bitmapWidth*bitmapHeight *4 bytes
我们读取的是 drawable 目录下面的图片,用的是 decodeResource 方法,系统在读取这些目录下的图片时会对图片进行缩放,这也是需要考虑的。
Bitmap 在内存当中占用的大小其实取决于:
色彩格式,前面我们已经提到,如果是 ARGB8888 那么就是一个像素4个字节,如果是 RGB565 那就是2个字节
原始文件存放的资源目录(是 hdpi 还是 xxhdpi 可不能傻傻分不清楚哈)
目标屏幕的密度(所以同等条件下,红米在资源方面消耗的内存肯定是要小于三星S6的)
关于ARGB_8888、ALPHA_8、ARGB_4444、RGB_565的理解
A:透明度
R:红色
G:绿
B:蓝
Bitmap.Config ARGB_4444:每个像素占四位,即A=4,R=4,G=4,B=4,那么一个像素点占4+4+4+4=16位
Bitmap.Config ARGB_8888:每个像素占四位,即A=8,R=8,G=8,B=8,那么一个像素点占8+8+8+8=32位
Bitmap.Config RGB_565:每个像素占四位,即R=5,G=6,B=5,没有透明度,那么一个像素点占5+6+5=16位
Bitmap.Config ALPHA_8:每个像素占四位,只有透明度,没有颜色。
一般情况下我们都是使用的ARGB_8888,由此可知它是最占内存的,因为一个像素占32位,8位=1字节,所以一个像素占4字节的内存。假设有一张480x800的图片,如果格式为ARGB_8888,那么将会占用1500KB的内存。
三.android的底层图片库
底层使用的是Skia库、libJpeg库。
http://www.cnblogs.com/hrlnw/p/4403334.html
http://www.kuqin.com/shuoit/20140826/341828.html?url_type=39&object_type=crawler&pos=1
四.android巨图加载方案
巨图加载,当然不能使用常规方法,必OOM。原理比较简单,系统中有一个类BitmapRegionDecoder。有个第三方可借鉴SubsamplingScaleImageView。
http://www.lai18.com/content/6705664.html
五.Android加载不同DPI资源与内存消耗间的关系
参考资料
Android Bitmap Api总结和使用方法
http://blog.csdn.net/shell812/article/details/49781255
Android中图形图片及处理相关Api的小总结
http://blog.csdn.net/zjngogo/article/details/49665113
API Demo学习——android Bitmap学习总结
http://blog.sina.com.cn/s/blog_5da93c8f0100w3xz.html
Bitmap(位图)全解析 Part 1
http://www.kancloud.cn/kancloud/android-tutorial/87244
Android 加载不同 DPI 资源与内存消耗间的关系
http://www.tinylab.org/android-loading-a-different-relationship-between-dpi-and-memory-consumption-of-resources/
http://m.blog.csdn.net/article/details?id=7856519
以上是关于APP性能优化系列:内存优化-bitmap详解的主要内容,如果未能解决你的问题,请参考以下文章
Android 进阶——性能优化之Bitmap位图内存管理及优化
Android 进阶——性能优化之Bitmap位图内存管理及优化
Android 进阶——性能优化之Bitmap位图内存管理及优化