在做内存优化的时候,我们发现除了解决内存泄露问题,剩下的就只有想办法减少真实的内存占用。而在 App 中,大部分内存可能被我们图片占用了,所以减少图片的内存占用可以带来直接的效果。
我们先假设我们有一张图片是 600 * 800 像素的,图片磁盘占用空间大小假设是 100KB。
图片内存大小跟磁盘占用空间大小有什么关系?
磁盘占用空间的大小不是图片占用内存的大小,磁盘占用空间是在磁盘上存储图片需要的一个空间大小,内存大小是加载到内存中占用的内存大小。两个只是单位是一样的,本质不是一个概念。
一张图片到底占用多少内存呢?
图片占用内存的计算公式是:图片高度 * 图片宽度 * 一个像素占用的内存大小,在 Android 中一般情况下默认一个像素占用内存是 4 个字节,所以上面的图片占用内存是:800 * 600 * 4 byte = 1875KB = 1.83M。为什么是 4 个字节呢?一定是 4 个字节么?这两个问题后面仔细讲。
图片所在目录对内存的影响?
在 Android 中,图片的存放目录和手机的屏幕密度影响图片最终加载到内存的实际大小,举个例子:假设我们的图片放到 xhdpi 目录下,那么我们本文中的图片占用的内存大小如下.
所以,计算图片占用内存大小的时候,要考虑图片所在的目录跟屏幕密度,这两个因素其实影响的是图片的高宽,Android 会对图片进行拉升跟压缩。
图片的内存占用计算方式为:图片高度 * 图片宽度 * 一个像素占用的内存大小,所以图片的高宽如果都变为原来宽高的 2 倍,那么内存将变为原来的 4 倍。所以图片的使用原则可以总结如下:
比如要实现一个线性渐变效果可以采用以下 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。
在不考虑透明度的情况下,一个像素点的颜色值在计算机中的表示方法有以下 3 种:
在 Java 中,float 类型的变量占 32 位,int 类型的变量占 32 位,short 和 char 类型的变量都在 16 位,因此可以看出,用浮点数表示法编码一个像素的颜色,内存占用量是 96 位即 12 字节;而用 24 位整数表示法编码,只要一个 int 类型变量,占用 4 个字节(高 8 位空着,低 24 位用于表示颜色);用 16 位整数表示法编码,只要一个 short 类型变量,占 2 个字节;因此可以看出采用整数表示法编码颜色值,可以大大节省内存,当然,颜色质量也会相对低一些。在 Android 中获取 Bitmap 的时候一般也采用整型编码。
在 Android 的 Bitmap.Config 类中,有 ARGB_8888、ARGB_4444、RGB565 等常量,现在可以知道它们分别代表了什么含义。
在 Android 中系统默认使用的编码格式是 ARGB_8888,所以在文章开头计算图片内存大小的时候每个像素占用内存大小是 4byte,比如采用 ARGB_8888 编码载入一张 1920*1200 的图片,大概就会占用 1920*1200*4/1024/1024=8.79MB 的内存。
采用低内存占用量的编码方式,比如 Bitmap.Config.ARGB_4444 比 Bitmap.Config.ARGB_8888 更省内存,比如 1920*1200 的图片。
在 Android 中,对图片的使用一定要关注,大多数情况下,占用内存多,OOM 发生都是因为图片资源使用不当。不要盲目加一个大图到 Android 项目中,能使用. 9 进来使用,而且. 9 图本身尽可能小,另外能使用绘制实现就不要加一个图片资源。有些时候,在不影响用户体验的情况下,可以降低图片色彩质量,比如不需要透明度的就不要了,有些透明度用肉眼看不出来。
来源: http://www.cnblogs.com/popfisher/p/7249562.html