Android高效内存:让图片占用尽可能少的内存

一、让你的图片最小化

1.1 大图小图内存使用情况对比

大图:440 * 336    小图:220 * 168 资源目录:xhdpi

小图的高宽都是大图的1/2-->小图是原图的1/4

界面效果:



测试设备:Coolpad   8676-M01   5.1   density=2.0

测试前准备操作:同一款设备,设置图片前后多次调用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   density=3.0

大图占用内存:13.22 MB - 11.95 MB = 1.27 MB

小图占用内存:12.27 MB - 11.95 MB = 0.32 MB

大图小图内存关系:0.32 MB * 4 = 1.28 MB 约等于 1.27 MB

结论:由此可见大图比小图占用更多的内存,图片大小(分辨率)与占用内存成正比关系

备注:图片在硬盘上占用的磁盘空间大小,与在内存中占用的内存大小完全不一样,不是一个概念,不要混淆

1.2 使用.9图代替大图

  根据上文中图片大小与内存的关系,可以更加深刻的理解Android中.9图片的作用,它不但能减少apk的体积,还能减少图片占用内存。

1.3 使用绘制背景或者Drawable代替图片

  有些时候我们根本不需要图片,而是自己绘制背景,可以在自定义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标签定义)静态使用和动态使用(圆角,渐变实现)

二、让你的图片省内存

2.1 “让你的图片最小化”

  “让你的图片最小化”一节中描述的方法:使用尽可能小的图,使用.9,自己绘制背景或者使用Drawable来绘制背景

2.2 在内存中压缩图片

  加载大图片时需要对图片进行压缩,使用等比例压缩方法直接在内存中处理图片

Options options = new BitmapFactory.Options();
options.inSampleSize = 5; // 原图的五分之一,设置为2则为二分之一
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.id.myimage, options);

  这样做要注意的是,图片质量会变差,inSampleSize设置的值越大,图片质量就越差。

2.3 读取位图尺寸和类型时不把图片加载到内存中

  有时候我们取得一张图片,也许只是为了获得这个图片的一些信息,比如图片的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;

2.4 用完就回收

  由于Android外层是使用java,而底层使用的是C语言为图片对象分配的内存空间。所以我们的外部虽然看起来释放了,但里层却并不一定完全释放了,我们使用完图片后最好再释放掉里层的内存空间。

if (!bitmapObject.isRecyled()) {    // Bitmap对象没有被回收
bitmapObject.recycle(); // 释放
System.gc(); // 提醒系统及时回收
}

2.5 降低要显示的图片色彩质量

2.5.1 颜色模型

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也称作印刷色彩模式,顾名思义就是用来印刷的。印刷四分色模式是彩色印刷时采用的一种套色模式,利用色料的三原色混色原理,加上黑色油墨,共计四种颜色混合叠加,形成所谓“全彩印刷”。四种标准颜色是:

  • C:Cyan = 青色,又称为‘天蓝色’或是‘湛蓝’
  • M:Magenta = 品红色,又称为‘洋红色’
  • Y:Yellow = 黄色
  • K:Key(blacK) = 定位套版色(黑色),有些文献解释说这里的K指代Black黑色,且为了避免与RGB的Blue蓝色混淆不用B而改称,虽然这是一种有用的助忆,但事实上这种说法是不正确的。

  CMYK和RGB相比有一个很大的不同:RGB模式是一种发光的色彩模式,你在一间黑暗的房间内仍然可以看见屏幕上的内容;CMYK是一种依靠反光的色彩模式,我们是怎样阅读报纸的内容呢?是由阳光或灯光照射到报纸上,再反射到我们的眼中,才看到内容。它需要有外界光源,如果你在黑暗房间内是无法阅读报纸的。只要是在印刷品上看到的图像,就是CMYK模式表现的。比如期刊、杂志、报纸、宣传画等,都是印刷出来的,那么就是CMYK模式的了。

CMYK原色与叠加之后的颜色对比

2.5.2 RGB在计算机中颜色值的数字化编码

  在不考虑透明度的情况下,一个像素点的颜色值在计算机中的表示方法有以下3种:

  1. 浮点数编码:比如float: (1.0, 0.5, 0.75),每个颜色分量各占1个float字段,其中1.0表示该分量的值为全红或全绿或全蓝;
  2. 24位的整数编码:比如24-bit:(255, 128, 196),每个颜色分量各占8位,取值范围0-255,其中255表示该分量的值为全红或全绿或全蓝;
  3. 16位的整数编码:比如16-bit:(31, 45, 31),第1和第3个颜色分量各占5位,取值范围0-31,第2个颜色分量占6位,取值范围0-63;

  在Java中,float类型的变量占32位,int类型的变量占32位,short和char类型的变量都在16位,因此可以看出,用浮点数表示法编码一个像素的颜色,内存占用量是96位即12字节;而用24位整数表示法编码,只要一个int类型变量,占用4个字节(高8位空着,低24位用于表示颜色);用16位整数表示法编码,只要一个short类型变量,占2个字节;因此可以看出采用整数表示法编码颜色值,可以大大节省内存,当然,颜色质量也会相对低一些。在Android中获取Bitmap的时候一般也采用整型编码。

2.5.3 Android中RGB编码格式(整型编码)

  • RGB888(int):R、G、B分量各占8位
  • RGB565(short):R、G、B分量分别占5、6、5位
  • RGB555(short):RGB分量都用5位表示(剩下的1位不用)
  • ARGB8888(int):A、R、G、B分量各占8位
  • ARGB4444(short):A、R、G、B分量各占4位

  回想一下Android的BitmapConfig类中,有ARGB_8888、ARGB_4444、RGB565等常量,现在可以知道它们分别代表了什么含义。同时也可以计算一张图片在内存中可能占用的大小,比如采用ARGB_8888编码载入一张1920*1200的图片,大概就会占用1920*1200*4/1024/1024=8.79MB的内存。

2.5.4 降低要显示的图片色彩质量

  采用低内存占用量的编码方式,比如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图本身尽可能小,另外能使用绘制实现就不要加一个图片资源。有些时候,在不影响用户体验的情况下,可以降低图片素材质量,比如不需要透明度的就不要了,有些透明度用肉眼看不出来。

Android高效内存:让图片占用尽可能少的内存的更多相关文章

  1. Android高效内存2:让图片占用尽可能少的内存

    Android高效内存:让图片占用尽可能少的内存 一.让你的图片最小化 1.1 大图小图内存使用情况对比 大图:440 * 336    小图:220 * 168 资源目录:xhdpi 小图的高宽都是 ...

  2. Android高效内存之让你的图片省内存

    Android高效内存之让你的图片省内存 在做内存优化的时候,我们发现除了解决内存泄露问题,剩下的就只有想办法减少真实的内存占用.而在App中,大部分内存可能被我们图片占用了,所以减少图片的内存占用可 ...

  3. android 图片占用内存与什么有关

    android 图片占用内存与什么有关 原文链接:http://blog.csdn.net/zjl5211314/article/details/7041813 在开发手机应用的时候,内存是有限的,那 ...

  4. Android中图片占用内存的计算

    Android中图片占用内存的计算 原文链接 http://blog.sina.com.cn/s/blog_4e60b09d01016133.html   在Android开发中,我现在发现很多人还不 ...

  5. Android高效内存1:一张图片占用多少内存

    在做内存优化的时候,我们发现除了解决内存泄露问题,剩下的就只有想办法减少真实的内存占用.而在App中,大部分内存可能被我们图片占用了,所以减少图片的内存占用可以带来直接的效果.本文就简单介绍一张图片到 ...

  6. 关于Android应用中图片占用内存浅谈

    从事过移动端应用开发的童鞋应该都清楚,内存是非常宝贵的资源.如果能很好的利用有限的内存,对应用性能的提升会有很大的帮助.在实际应用开发中图片内存占整个应用非常大的比重,我们只有了解图片是如何加载到内存 ...

  7. (转)Android中图片占用内存计算

    在Android开发中,我现在发现很多人还不会对图片占用内存进行很好的计算.因此撰写该博文来做介绍,期望达到抛砖引玉的作用.   Android中一张图片(BitMap)占用的内存主要和以下几个因数有 ...

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

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

  9. android 网络加载图片,对图片资源进行优化,并且实现内存双缓存 + 磁盘缓存

    经常会用到 网络文件 比如查看大图片数据 资源优化的问题,当然用开源的项目  Android-Universal-Image-Loader  或者 ignition 都是个很好的选择. 在这里把原来 ...

随机推荐

  1. wemall app商城源码中基于JAVA的绑定和处理fragments和viewpager之间的逻辑关系代码

    wemall doraemon是Android客户端程序,服务端采用wemall微信商城,不对原商城做任何修改,只需要在原商城目录下上传接口文件即可完成服务端的配置,客户端可随意定制修改.本文分享其中 ...

  2. iOS截屏保存至相册

    #pragma mark 截屏并保存至相册 -(void)screenShotsComplete:(void(^)(UIImage * img)) complete { CGSize imageSiz ...

  3. html中submit和button的区别(总结) [ 转自欣步同学 ]

    html中submit和button的区别(总结) submit是button的一个特例,也是button的一种,它把提交这个动作自动集成了. 如果表单在点击提交按钮后需要用JS进行处理(包括输入验证 ...

  4. echarts柱图自定义为硬币堆叠的形式

    看这标题,可能会有一些人不太明白,那么直接上图,就是柱图展示形式如下图(兼容IE8) 要想实现这样展示效果.我们想用echarts直接实现不行的,即使是纹理填充也不可行的,但是我们可以借助echart ...

  5. HDFS入门(1)

    2015.07.12笔记 1.HDFS Distributed File System(操作系统实现人机交互,最重要的功能是文件管理,使用文件管理系统,windows.Linux文件管理系统有共性:用 ...

  6. 打印时鼠标键盘移动的div创建

    function createDiv(id, label, offset_left, offset_top) { $("body").append($("<div& ...

  7. SQLServer中间接实现函数索引或者Hash索引

    本文出处:http://www.cnblogs.com/wy123/p/6617700.html SQLServer中没有函数索引,在某些场景下查询的时候要根据字段的某一部分做查询或者经过某种计算之后 ...

  8. 学习Redux之分析Redux核心代码分析

    1. React,Flux简单介绍 学习React我们知道,React自带View和Controller库,因此,实现过程中不需要其他任何库,也可以独立开发应用.但是,随着应用程序规模的增大,其需要控 ...

  9. Alamofire源码解读系列(十一)之多表单(MultipartFormData)

    本篇讲解跟上传数据相关的多表单 前言 我相信应该有不少的开发者不明白多表单是怎么一回事,然而事实上,多表单确实很简单.试想一下,如果有多个不同类型的文件(png/txt/mp3/pdf等等)需要上传给 ...

  10. Cobbler自动化部署最佳实践

    第1章 Cobbler自动化部署最佳实践 运维自动化在生产环境中占据着举足轻重的地位,尤其是面对几百台,几千台甚至几万台的服务器时,仅仅是安装操作系统,如果不通过自动化来完成,根本是不可想象的. 面对 ...