android内存优化之图片优化
程序员文章站
2023-12-14 18:51:22
对图片本身进行操作。尽量不要使用setimagebitmap、setimageresource、bitmapfactory.decoderesource来设置一张大图,因为...
对图片本身进行操作。尽量不要使用setimagebitmap、setimageresource、bitmapfactory.decoderesource来设置一张大图,因为这些方法在完成decode后,最终都是通过java层的createbitmap来完成的,需要消耗更多内存。因此,改用先通过bitmapfactory.decodestream方法,创建出一个bitmap,再将其设为imageview的source,decodestream最大的秘密在于其直接调用jni>>nativedecodeasset()来完成decode,无需再使用java层的createbitmap,从而节省了java层的空间。如果在读取时加上图片的config参数,可以更有效的减少加载的内存,从而更有效阻止抛出内存异常。另外,decodestream直接拿图片来读取字节码了,不会根据机器的各种分辨率来自动适应,使用了decodestream之后,需要在hdpi和mdpi,ldpi中配置相应的图片资源,否则在不同分辨率机器上都是同样大小(像素点数量),显示出来的大小就不对了。
复制代码 代码如下:
inputstreamis=this.getresources().openrawresource(r.drawable.pic1);
bitmapfactory.optionsoptions=newbitmapfactory.options();
options.injustdecodebounds=false;
options.insamplesize=10;//width,hight设为原来的十分一
bitmapbtp=bitmapfactory.decodestream(is,null,options);
复制代码 代码如下:
if(!bmp.isrecycle()){
bmp.recycle()//回收图片所占的内存
system.gc()//提醒系统及时回收
}
复制代码 代码如下:
/**
*以最省内存的方式读取本地资源的图片
*@paramcontext
*@paramresid
*@return
*/
publicstaticbitmapreadbitmap(contextcontext,intresid){
bitmapfactory.optionsopt=newbitmapfactory.options();
opt.inpreferredconfig=bitmap.config.rgb_565;
opt.inpurgeable=true;
opt.ininputshareable=true;
//获取资源图片
inputstreamis=context.getresources().openrawresource(resid);
returnbitmapfactory.decodestream(is,null,opt);
}
option中的值指的是,图片进行缩放的比例,sdk中建议其值是2的指数值,值越大会导致图片不清晰。长度、宽度都只有原图片的1/2。图片大小减少,占用的内存自然也变小了。这么做的弊端是图片质量变差,insamplesize的值越大,图片的质量就越差。由于各手机厂商缩放图片的算法不同,在不同手机上的缩放图片质量可能会不同。笔者就遭遇过moto手机上图片缩放后质量可以接受,三星手机上同样的缩放比例,质量却差很多的情况。
android中有四种,分别是:
alpha_8:每个像素占用1byte内存
argb_4444:每个像素占用2byte内存
argb_8888:每个像素占用4byte内存
rgb_565:每个像素占用2byte内存
android默认的颜色模式为argb_8888,这个颜色模式色彩最细腻,显示质量最高。但同样的,占用的内存也最大。
以上代码即是将1.png以argb_4444模式读出。内存减少虽然不如第一种方法明显,但是对于大多数图片,看不出与argb_8888模式有什么差别。不过在读取有渐变效果的图片时,可能有颜色条出现。另外,会影响图片的特效处理。
优化dalvik虚拟机的堆内存分配。对于android平台来说,其托管层使用的dalvikjavavm从目前的表现来看还有很多地方可以优化处理,比如我们在开发一些大型游戏或耗资源的应用中可能考虑手动干涉gc处理,使用dalvik.system.vmruntime类提供的settargetheaputilization方法可以增强程序堆内存的处理效率。使用方法:
复制代码 代码如下:
privatefinalstaticfloattarget_heap_utilization=0.75f;
vmruntime.getruntime().settargetheaputilization(target_heap_utilization);
即可。
还有就是可以定义堆内存的大小。
复制代码 代码如下:
privatefinalstaticintcwj_heap_size=6*1024*1024;vmruntime.getruntime().setminimumheapsize(cwj_heap_size);//设置最小heap内存为6mb大小
调用图片的recycle()方法:
这个其实不是真正降低图片内存的方法。主要目的是标记图片对象,方便回收图片对象的本地数据。图片对象的本地数据占用的内存最大,而且与程序java部分的内存是分开计算的。所以经常出现javaheap足够使用,而图片发生outofmemoryerror的情况。在图片不使用时调用该方法,可以有效降低图片本地数据的峰值,从而减少outofmemoryerror的概率。不过调用了recycle()的图片对象处于“废弃”状态,调用时会造成程序错误。所以在无法保证该图片对象绝对不会被再次调用的情况下,不建议使用该方法。特别要注意已经用setimagebitmap(bitmapimg)方法分配给控件的图片对象,可能会被系统类库调用,造成程序错误。
使用matrix对象放大的图片如何更改颜色模式:
虽然使用matrix对象放大图片,必定会耗费更多的内存,但有时候也不得不这样做。放大后的图片使用的argb_8888颜色模式,就算原图片是argb_4444颜色模式也一样,而且没有办法在放大时直接指定颜色模式。可以采用以下办法更改图片颜色模式。
代码如下
复制代码 代码如下:
matrixmatrix=newmatrix();
floatnewwidth=200;//图片放大后的宽度
floatnewheight=300;//图片放大后的长度
matrix.postscale(newwidth/img.getwidth(),newheight/img.getheight());
bitmapimg1=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,所以实际内存还是减少了。