大图:440 * 336 小图:220 * 168
小图的高宽都是大图的 1/2--> 小图是原图的 1/4
界面效果: 测试设备:Coolpad 8676-M01 5.1
测试前准备操作:同一款设备,设置图片前后多次调用 gc 直到内存短时间内保持稳定不再变化
内存使用情况:下图依次是 初始内存,大图内存,小图内存 大图占用内存:11.23 MB - 10.66 MB = 0.57 MB
小图占用内存:10.81 MB - 10.66 MB = 0.15 MB
大图小图内存关系:0.15 MB * 4 = 0.60 MB 约等于 0.57 MB (这是统计工具的误差,理论上就是相等的)
同样的方式在另外一台设备小米 4c 上得到的结果如下:
测试设备:Xiaomi Mi-4c V8.2.1.0.LXKCNDL 5.1.1
大图占用内存:13.22 MB - 11.95 MB = 1.27 MB
小图占用内存:12.27 MB - 11.95 MB = 0.32 MB
大图小图内存关系:0.32 MB * 4 = 12.8 MB 约等于 1.27 MB
结论:由此可见大图比小图占用更多的内存,图片大小(分辨率)与占用内存成正比关系
备注:图片在硬盘上占用的磁盘空间大小,与在内存中占用的内存大小完全不一样,不是一个概念,不要混淆
根据上文中图片大小与内存的关系,可以更加深刻的理解 Android 中. 9 图片的作用,它不但能减少 apk 的体积,还能减少图片占用内存。
有些时候我们根本不需要图片,而是自己绘制背景,可以在自定义 View 的 onDraw 中绘制背景,当然最方便的还是使用系统的 Drawable,绘制部分交给系统去完成。下面测试图片与 Drawable 的内存占用对比
原始图片大小:482 * 482 界面效果: 测试设备:Xiaomi Mi-4c V8.2.1.0.LXKCNDL 5.1.1
测试前准备操作:同一款设备,设置背景前后多次调用 gc 直到内存短时间内保持稳定不再变化
内存使用情况:下图依次是 初始内存,使用图片占用的内存,使用 Drawable 占用的内存,使用 onDraw 绘制占用的内存 使用图片占用内存:13.97 MB - 11.97 MB = 2.00 MB
使用 Drawable 占用内存:11.97 MB - 11.97 MB = 0.00 MB (不会是 0,有误差,只是很少)
使用 onDraw 绘制占用内存:11.98 MB - 11.97 MB = 0.01 MB
结论:绘制背景,或者使用系统提供 Drawable 作为背景,会大大减少内存占用
Drawable 参考资料:
Drawable 实战解析:Android XML shape 标签使用详解(apk 瘦身,减少内存好帮手)
Android GradientDrawable(shape 标签定义)静态使用和动态使用 (圆角,渐变实现)
"让你的图片最小化" 一节中描述的方法:使用尽可能小的图,使用. 9,自己绘制背景或者使用 Drawable 来绘制背景
加载大图片时需要对图片进行压缩,使用等比例压缩方法直接在内存中处理图片
- Options options = new BitmapFactory.Options();
- options.inSampleSize = 5; // 原图的五分之一,设置为2则为二分之一
- Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
这样做要注意的是,图片质量会变差,inSampleSize 设置的值越大,图片质量就越差。
有时候我们取得一张图片,也许只是为了获得这个图片的一些信息,比如图片的 width、height 等信息,不需要显示到界面上,这个时候我们可以不把图片加载到内存中。
- 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;
由于 Android 外层是使用 java,而底层使用的是 C 语言为图片对象分配的内存空间。所以我们的外部虽然看起来释放了,但里层却并不一定完全释放了,我们使用完图片后最好再释放掉里层的内存空间。
- if (!bitmapObject.isRecyled()) { // Bitmap对象没有被回收
- bitmapObject.recycle(); // 释放
- System.gc(); // 提醒系统及时回收
- }
RGB(ARGB)
RGB 色彩模式是工业界的一种颜色标准,是通过对红 (R)、绿(G)、蓝(B) 三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB 即是代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是目前运用最广的颜色系统之一。在 Android 中还有包含透明度 Alpha 的颜色模型,即 ARGB。 YUV
YUV,分为三个分量,"Y" 表示明亮度(Luminance 或 Luma),也就是灰度值;而 "U" 和 "V" 表示的则是色度(Chrominance 或 Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。
YUV 的原理是把亮度与色度分离,研究证明,人眼对亮度的敏感超过色度。利用这个原理,可以把色度信息减少一点,人眼也无法查觉这一点。
主要用于电视系统以及模拟视频领域,它将亮度信息(Y)与色彩信息(UV)分离,没有 UV 信息一样可以显示完整的图像,只不过是黑白的,这样的设计很好地解决了彩色电视机与黑白电视的兼容问题
YUV 的存储中与 RGB 格式最大不同在于,RGB 格式每个点的数据是连继保存在一起的。即 R,G,B 是前后不间隔的保存在 2-4byte 空间中。而 YUV 的数据中为了节约空间,U,V 分量空间会减小。每一个点的 Y 分量独立保存,但连续几个点的 U,V 分量是保存在一起的,(反正人眼一般也看不出区别). 这几个点合起来称为 macro-pixel, 这种存储格式称为 Packed 格式。另外一种存储格式是把一幅图像中 Y,U,V 分别用三个独立的数组表示。这种模式称为 planar 模式。
CMYK CMYK 也称作印刷色彩模式,顾名思义就是用来印刷的。它和 RGB 相比有一个很大的不同:RGB 模式是一种发光的色彩模式,你在一间黑暗的房间内仍然可以看见屏幕上的内容;CMYK 是一种依靠反光的色彩模式,我们是怎样阅读报纸的内容呢?是由阳光或灯光照射到报纸上,再反射到我们的眼中,才看到内容。它需要有外界光源,如果你在黑暗房间内是无法阅读报纸的。只要是在印刷品上看到的图像,就是 CMYK 模式表现的。比如期刊、杂志、报纸、宣传画等,都是印刷出来的,那么就是 CMYK 模式的了。
在不考虑透明度的情况下,一个像素点的颜色值在计算机中的表示方法有以下 3 种:
在 Java 中,float 类型的变量占 32 位,int 类型的变量占 32 位,short 和 char 类型的变量都在 16 位,因此可以看出,用浮点数表示法编码一个像素的颜色,内存占用量是 96 位即 12 字节;而用 24 位整数表示法编码,只要一个 int 类型变量,占用 4 个字节(高 8 位空着,低 24 位用于表示颜色);用 16 位整数表示法编码,只要一个 short 类型变量,占 2 个字节;因此可以看出采用整数表示法编码颜色值,可以大大节省内存,当然,颜色质量也会相对低一些。在 Android 中获取 Bitmap 的时候一般也采用整型编码。
回想一下 Android 的 BitmapConfig 类中,有 ARGB_8888、ARGB_4444、RGB565 等常量,现在可以知道它们分别代表了什么含义。同时也可以计算一张图片在内存中可能占用的大小,比如采用 ARGB_8888 编码载入一张 1920*1200 的图片,大概就会占用 1920*1200*4/1024/1024=8.79MB 的内存。
采用低内存占用量的编码方式,比如 Bitmap.Config.ARGB_4444 比 Bitmap.Config.ARGB_8888 更省内存;
1920*1200 的图片:
ARGB_8888:1920*1200*4/1024/1024=8.79MB
ARGB_4444,RGB565:1920*1200*2/1024/1024=4.39MB
在 Android 中,对图片的使用一定要关注,大多数情况下,占用内存多,OOM 发生都是因为图片资源使用不当。不要盲目加一个大图到 Android 项目中,能使用. 9 进来使用,而且. 9 图本身尽可能小,另外能使用绘制实现就不要加一个图片资源。有些时候,在不影响用户体验的情况下,可以降低图片素材质量,比如不需要透明度的就不要了,有些透明度用肉眼看不出来。
来源: http://www.cnblogs.com/popfisher/p/6770018.html