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

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

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

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

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

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

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

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

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

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

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

  在Android的Bitmap.Config类中,有ARGB_8888、ARGB_4444、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

三、总结

  在Android中,对图片的使用一定要关注,大多数情况下,占用内存多,OOM发生都是因为图片资源使用不当。不要盲目加一个大图到Android项目中,能使用.9进来使用,而且.9图本身尽可能小,另外能使用绘制实现就不要加一个图片资源。有些时候,在不影响用户体验的情况下,可以降低图片色彩质量,比如不需要透明度的就不要了,有些透明度用肉眼看不出来。

Android高效内存之让你的图片省内存的更多相关文章

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

    Android高效内存:让图片占用尽可能少的内存 一.让你的图片最小化 1.1 大图小图内存使用情况对比 大图:440 * 336    小图:220 * 168 小图的高宽都是大图的1/2--> ...

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

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

  3. Android高效加载大图、多图解决方案,有效避免程序内存溢出现象

    好久没有写博客了,今天就先写一个小的关于在Android中加载大图如何避免内存溢出的问题. 后面会写如何使用缓存技术的核心类,android.support.v4.util.LruCache来加载图片 ...

  4. Android高效异步图片加载框架

    概述 Android高效异步图片加载框架:一个高效的异步加载显示的图片加载框架,同时具备图片压缩,缓存机制等特性. 详细 代码下载:http://www.demodashi.com/demo/1214 ...

  5. [Android]异步加载图片,内存缓存,文件缓存,imageview显示图片时增加淡入淡出动画

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/3574131.html  这个可以实现ImageView异步加载 ...

  6. Android 加载大图片到内存

    本文演示android中图片加载到内存 首先设计界面: 代码如下: <LinearLayout xmlns:android="http://schemas.android.com/ap ...

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

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

  8. Android 编程下图片的内存优化

    1. 对图片本身进行操作 尽量不要使用 setImageBitmap.setImageResource. BitmapFactory.decodeResource 来设置一张大图,因为这些方法在完成 ...

  9. 图片--Android加载图片导致内存溢出(Out of Memory异常)

    Android在加载大背景图或者大量图片时,经常导致内存溢出(Out of Memory  Error),本文根据我处理这些问题的经历及其它开发者的经验,整理解决方案如下(部分代码及文字出处无法考证) ...

随机推荐

  1. Mac OS中使用VScode配置C语言开发环境

    个人博客 chinazt.cc 闲话少叙,直奔主题 下载VSCode https://code.visualstudio.com/download 安装C/C++插件 需要两个插件: 1. cppto ...

  2. Chapter2:Discrete-Time Signal Processing and Short-Time Fourier Analysis

    作者:桂. 时间:2017-05-24  08:44:53 主要是<Speech enhancement: theory and practice>的读书笔记,全部内容可以点击这里. 这一 ...

  3. Ubuntu16.04更换漂亮绚丽flatabulous主题

    作者:tongqingliu 转载请注明出处: Ubuntu16.04更换漂亮绚丽flatabulous主题 更新 sudo apt-get update sudo apt-get upgrade 安 ...

  4. Strom序列化机制

    Storm 中的 tuple可以包含任何类型的对象.由于Storm 是一个分布式系统,所以在不同的任务之间传递消息时Storm必须知道怎样序列化.反序列化消息对象. Storm 使用 Kryo库对对象 ...

  5. watchdog(IWDG)

    1.为了避免程序忙跑跑死了没反应,加上一个看门狗watchdog实时监控着程序,一旦程序没有在规定的时间喂狗,则狗叫使得单片机复位. 2.Independent watchdog(IWDG)内部有时钟 ...

  6. Loadrunner12解决无法录制chrome及脚本为空问题

    首先,得安装LR12,一般用LR12录制,由于未破解,用LR11跑并发. LR12官方文档说明里是支持chrome及火狐的,但是实际录制起来,还是有一定的问题,目前发现的问题主要有两个: (1)LR录 ...

  7. alt和title的区别与用法

    alt和title的是我们工作中经常用到这两个属性,但是一直没有总结他们的区别.现在就对他们两个的用法做一下总结.相同点:他们都会飘出一个小浮层,显示文本内容.不同点:1.alt只能是元素的属性,而t ...

  8. Codeforces 818B Permutation Game

    首先看一下题目 B. Permutation Game time limit per test 1 second memory limit per test 256 megabytes input s ...

  9. [图形学] 习题8.6 线段旋转后使用Cohen-Sutherland算法裁剪

    习题8.6 生成一条比观察窗口对角线还长的线段动画,线段重点位于观察窗口中心,每一帧的线段在上一帧基础上顺时针旋转一点,旋转后用Cohen-Sutherland线段裁剪算法进行裁剪. 步骤: 1 视口 ...

  10. vijos1080题解

    题目: 对于一个递归函数w(a,b,c) 如果a<=0 or b<=0 or c<=0就返回值1. 如果a>20 or b>20 or c>20就返回w(20,20 ...