zl程序教程

您现在的位置是:首页 >  移动开发

当前栏目

Android中对于图片的内存优化方法

Android内存方法 优化 图片 对于
2023-06-13 09:14:47 时间

1.对图片本身进行操作

尽量不要使用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.pic);
BitmapFactory.Optionsoptions=newBitmapFactory.Options();
options.inJustDecodeBounds=false;
options.inSampleSize=2;
Bitmapbtp=BitmapFactory.decodeStream(is,null,options);

以上代码即是读取drawable下名为pic图片的缩略图,长度、宽度都只有原图片的1/2。图片大小减少,占用的内存自然也变小了。这么做的弊端是图片质量变差,inSampleSize的值越大,图片的质量就越差。由于各手机厂商缩放图片的算法不同,在不同手机上的缩放图片质量可能会不同。

2.调用图片的recycle()方法

复制代码代码如下:


if(!bmp.isRecycle()){
  bmp.recycle()   //回收图片所占的内存
  system.gc()     //提醒系统及时回收
}

这种方法其实不是真正降低图片内存的方法。主要目的是标记图片对象,方便回收图片对象的本地数据。图片对象的本地数据占用的内存最大,而且与程序Java部分的内存是分开计算的。所以经常出现Javaheap足够使用,而图片发生OutOfMemoryError的情况。在图片不使用时调用该方法,可以有效降低图片本地数据的峰值,从而减少OutOfMemoryError的概率。不过调用了recycle()的图片对象处于“废弃”状态,调用时会造成程序错误。所以在无法保证该图片对象绝对不会被再次调用的情况下,不建议使用该方法。特别要注意已经用setImageBitmap(Bitmap
img)方法分配给控件的图片对象,可能会被系统类库调用,造成程序错误。

 

3.以最省内存的方式读取本地资源的图片

复制代码代码如下:
/**
 *以最省内存的方式读取本地资源的图片
 */
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); 
}

Android中加载图片的颜色模式有四种,分别是:ALPHA_8:每个像素占用1byte内存、ARGB_4444:每个像素占用2byte内存、ARGB_8888:每个像素占用4byte内存、RGB_565:每个像素占用2byte内存。Android默认的颜色模式为ARGB_8888,这个颜色模式色彩最细腻,显示质量最高。但同样的,占用的内存也最大。以上代码即是将图片资源以RGB_565(或以ARGB_4444)模式读出。内存减少虽然不如第一种方法明显,但是对于大多数图片,看不出与ARGB_8888模式有什么差别。不过在读取有渐变效果的图片时,可能有颜色条出现。另外,会影响图片的特效处理。

 

4.使用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,所以实际内存还是削减了。

归结起来还是以缩略图模式读取图片和削减图片中每个像素占用的内存最为有效。这两种办法固然有效,然则也有各自的弊病。实际开辟中还是应当按照景象酌情应用。最王道的办法,还是避免垃圾对象的产生。例如在ListView的应用中,复用convertView等。若是应用AsyncTask加载图片,要及时将引用的ImageView对象置为null。因为AsyncTask是用线程池实现的,所以此中引用的对象可能会拥有很长的生命周期,造成GC无法开释。我还是信赖Android的内存收受接管机制的,recycle什么的固然必然程度上有效,但总感觉不合适Java内存收受接管的原则。