Android图片内存优化的几点心得
Admin 2012年6月24日 名人名言:时间就是
1、将图片转化为缩略图再加载:
1 BitmapFactory.Options options = new BitmapFactory.Options();2 options.inSampleSize = 2;3 Bitmap img = BitmapFactory.decodeFile("/sdcard/1.png", options);
该段代码便是读取1.png的缩略图,长度、宽度都只有原图片的1/2。图片大小削减,占用的内存天然也变小了。这么做的弊病是图片质量变差,inSampleSize的值越大,图片的质量就越差。因为各手机厂商缩放图片的算法不合,在不合手机上的缩放图片质量可能会不合。笔者就遭受过moto手机上图片缩放后质量可以接管,三星手机上同样的缩放比例,质量却差很多的景象。
2、用ARBG_4444色彩模式加载图片:
Android中有四种,分别是:
ALPHA_8:每个像素占用1byte内存
ARGB_4444:每个像素占用2byte内存
ARGB_8888:每个像素占用4byte内存
RGB_565:每个像素占用2byte内存
Android默认的色彩模式为ARGB_8888,这个色彩模式色彩最细腻,显示质量最高。但同样的,占用的内存也最大。
1 BitmapFactory.Options options = new BitmapFactory.Options();2 options.inPreferredConfig = Bitmap.Config.ARGB_4444; 3 Bitmap img = BitmapFactory.decodeFile("/sdcard/1.png", options);
以上代码便是将1.png以ARGB_4444模式读出。内存削减固然不如第一种办法明显,然则对于大多半图片,看不出与ARGB_8888模式有什么差别。不过在读取有渐变结果的图片时,可能有色彩条呈现。别的,会影响图片的殊效处理惩罚。
3、调用图片的recycle()办法:
这个其实不是真正降落图片内存的办法。首要目标是标识表记标帜图片对象,便利收受接管图片对象的本地数据。图片对象的本地数据占用的内存最大,并且与法度Java项目组的内存是分隔策画的。所以经常呈现Java heap足够应用,而图片产生OutOfMemoryError的景象。在图片不应用时调用该办法,可以有效降落图片本地数据的峰值,从而削减OutOfMemoryError的概率。不过调用了recycle()的图片对象处于“放弃”状况,调用时会造成法度错误。所以在无法包管该图片对象绝对不会被再次调用的景象下,不建议应用该办法。希罕要重视已经用setImageBitmap(Bitmap img)办法分派给控件的图片对象,可能会被体系类库调用,造成法度错误。
4、应用Matrix对象放大的图片如何更改色彩模式:
固然应用Matrix对象放大图片,必然会花费更多的内存,但有时辰也不得不如许做。放大后的图片应用的ARGB_8888色彩模式,就算原图片是ARGB_4444色彩模式也一样,并且没有办法在放大时直接指定色彩模式。可以采取以下办法更改图片色彩模式。
Matrix matrix = new Matrix();float newWidth = 200;//图片放大后的宽度float newHeight = 300;//图片放大后的长度matrix.postScale(newWidth / img.getWidth(), newHeight/ img.getHeight());Bitmap img1 = Bitmap.createBitmap(img, 0, 0, img.getWidth(), img.getHeight(), matrix, true);//获得放大的图片img2 = img1.copy(Bitmap.Config.ARGB_4444, false);//获得ARGB_4444色彩模式的图片img = null;img1 = null;
这里比起本来的图片额外生成了一个图片对象img1。然则体系会主动收受接管img1,所以实际内存还是削减了。
归结起来还是以缩略图模式读取图片和削减图片中每个像素占用的内存。这两种办法固然有效,然则也有各自的弊病。实际开辟中还是应当按照景象酌情应用。最王道的办法,还是避免垃圾对象的产生。例如在ListView的应用中,复用convertView等。若是应用AsyncTask加载图片,要及时将引用的ImageView对象置为null。因为AsyncTask是用线程池实现的,所以此中引用的对象可能会拥有很长的生命周期,造成GC无法开释。我还是信赖Android的内存收受接管机制的,recycle什么的固然必然程度上有效,但总感觉不合适Java内存收受接管的原则。(最后这句美满是着魔了)
补充...
尽量不要使用setImageBitmap或setImageResource 或BitmapFactory.decodeResource来设置一张大图, 因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的, 需要消耗更多内存. 因此,改用先通过BitmapFactory.decodeStream方法, 创建出一个bitmap,再将其设为ImageView的 source, decodeStream最大的秘密在于其直接调用 JNI >> nativeDecodeAsset() 来完成decode, 无需再使用java层的createBitmap,从而节省了java层的空间. 如果在读取时加上图片的Config参数,可以更有效减少加载的内存, 从而有效阻止抛出out of Memory异常 另外,decodeStream直接拿的图片来读取字节码了, 不会根据机器的各种分辨率来自动适应, 使用了decodeStream之后,需要在hdpi和mdpi,ldpi中配置相应的图片资源, 否则在不同分辨率机器上都是同样大小(像素点数量),显示出来的大小就不对了. BitmapFactory.Options.inPreferredConfig ALPHA_8:数字为8,图形参数应该由一个字节来表示,应该是一种8位的位图 ARGB_4444:4+4+4+4=16,图形的参数应该由两个字节来表示,应该是一种16位的位图. ARGB_8888:8+8+8+8=32,图形的参数应该由四个字节来表示,应该是一种32位的位图. RGB_565:5+6+5=16,图形的参数应该由两个字节来表示,应该是一种16位的位图. ALPHA_8,ARGB_4444,ARGB_8888都是透明的位图,也就是所字母A代表透明. ARGB_4444:意味着有四个参数,即A,R,G,B,每一个参数由4bit表示. ARGB_8888:意味着有四个参数,即A,R,G,B,每一个参数由8bit来表示. RGB_565:意味着有三个参数,R,G,B,三个参数分别占5bit,6bit,5bit. BitmapFactory.Options.inPurgeable; 如果 inPurgeable 设为True的话表示使用BitmapFactory创建的Bitmap 用于存储Pixel的内存空间在系统内存不足时可以被回收, 在应用需要再次访问Bitmap的Pixel时(如绘制Bitmap或是调用getPixel), 系统会再次调用BitmapFactory decoder重新生成Bitmap的Pixel数组. 为了能够重新解码图像,bitmap要能够访问存储Bitmap的原始数据. 在inPurgeable为false时表示创建的Bitmap的Pixel内存空间不能被回收, 这样BitmapFactory在不停decodeByteArray创建新的Bitmap对象, 不同设备的内存不同,因此能够同时创建的Bitmap个数可能有所不同, 200个bitmap足以使大部分的设备重新OutOfMemory错误. 当isPurgable设为true时,系统中内存不足时, 可以回收部分Bitmap占据的内存空间,这时一般不会出现OutOfMemory 错误.