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

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

       在作内存优化的时候,咱们发现除了解决内存泄露问题,剩下的就只有想办法减小真实的内存占用。而在App中,大部份内存可能被咱们图片占用了,因此减小图片的内存占用能够带来直接的效果。java

1、一张图片到底占用多少内存

  咱们先假设咱们有一张图片是600 * 800像素的,图片磁盘占用空间大小假设是 100KB。android

图片内存大小跟磁盘占用空间大小有什么关系?优化

  磁盘占用空间的大小不是图片占用内存的大小,磁盘占用空间是在磁盘上存储图片须要的一个空间大小,内存大小是加载到内存中占用的内存大小。两个只是单位是同样的,本质不是一个概念。编码

一张图片到底占用多少内存呢?spa

  图片占用内存的计算公式是:图片高度 * 图片宽度 * 一个像素占用的内存大小,在Android中通常状况下默认一个像素占用内存是4个字节,因此上面的图片占用内存是:800 * 600 * 4 byte = 1875KB = 1.83M。为何是4个字节呢?必定是4个字节么?这两个问题后面仔细讲。code

图片所在目录对内存的影响?对象

  在Android中,图片的存放目录和手机的屏幕密度影响图片最终加载到内存的实际大小,举个例子:假设咱们的图片放到xhdpi目录下,那么咱们本文中的图片占用的内存大小以下.blog

  • 屏幕密度为2的设备:800 * 600 * 4byte = 1.83M
  • 屏幕密度为3的设备:800 * 1.5 * 600 * 1.5 * 4byte = 1.83 * 2.25M = 4.12M
  • 这里所说的屏幕密度是指android.util.DisplayMetrics类中的density变量,是一个float值,关于屏幕密度的更多内容本文不作介绍。

  

  因此,计算图片占用内存大小的时候,要考虑图片所在的目录跟屏幕密度,这两个因素其实影响的是图片的高宽,Android会对图片进行拉升跟压缩。图片

2、 让你的图片省内存

2.1 让你的图片最小化

  图片的内存占用计算方式为:图片高度 * 图片宽度 * 一个像素占用的内存大小,因此图片的高宽若是都变为原来宽高的2倍,那么内存将变为原来的4倍。因此图片的使用原则能够总结以下:内存

  1. 使用尽量小的图
  2. 使用.9图,.9图自己也要尽量的小
  3. 本身绘制(覆写View的onDraw本身画)或者使用Drawable来绘制

好比要实现一个线性渐变效果能够采用如下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。

 

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位
  • RGB555(short):RGB份量都用5位表示(剩下的1位不用)
  • ARGB8888(int):A、R、G、B份量各占8位
  • ARGB4444(short):A、R、G、B份量各占4位

  在Android的Bitmap.Config类中,有ARGB_888八、ARGB_444四、RGB565等常量,如今能够知道它们分别表明了什么含义。

 

  在Android中系统默认使用的编码格式是ARGB_8888,因此在文章开头计算图片内存大小的时候每一个像素占用内存大小是4byte,好比采用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

3、总结

  在Android中,对图片的使用必定要关注,大多数状况下,占用内存多,OOM发生都是由于图片资源使用不当。不要盲目加一个大图到Android项目中,能使用.9进来使用,并且.9图自己尽量小,另外能使用绘制实现就不要加一个图片资源。有些时候,在不影响用户体验的状况下,能够下降图片色彩质量,好比不须要透明度的就不要了,有些透明度用肉眼看不出来。

相关文章
相关标签/搜索