使用Bitmap--避免OOM内存溢出

来源:互联网 发布:数组slice js 编辑:程序博客网 时间:2024/05/17 13:10

1.Bitmap的使用技巧

  尽量不要使用 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中配置相应的图片资源, 否则在不同分辨率机器上都是同样大小(像素点数量),显示出来的大小就不对了。  


2.使用BitmapFactory.Options

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 错误。 


BitmapFactory.Options.inSampleSize

     * 缩小图片的宽高比例值

     * inSampleSize为整形数值,如果复制为2,则将图片的宽高缩小为原图片的二分之一


  根据屏幕的密度对图片进行缩放,因此我们使用最大的图片资源,这样的话对于任何的手机屏幕,都会对图像进行压缩,不会造成视觉上的问题。图片解码前需要对BitmapFactory.Options进行设置,部分代码如下:

BitmapFactory.Options options = new BitmapFactory.Options();DisplayMetrics displayMetrics = context.getResources.getDisplayMetrics();......options.inTargetDensity = displayMetrics.densityDpi;options.inScaled = true;//getBitmapDensity()用于设置图片将要被显示的密度。options.inDensity = getBitmapDensity();......Bitmap bitmap = getBitmapFromPath(loadPath, options);
  options.inTargetDensity表示的是目标Bitmap即将被画到屏幕上的像素密度(每英寸有多少个像素)。这个属性往往会和options.inDensity和options.inScaled一起来觉得目标bitmap是否需要进行缩放。若果这个值为0,则BitmapFactory.decodeResource(Resources, int)和BitmapFactory.decodeResource(Resources, int, android.graphics.BitmapFactory.Options)、decodeResourceStream(Resources, TypedValue, InputStream, Rect, BitmapFactory.Options) 将inTargetDensity用DisplayMetrics.densityDpi来设置,其它函数则不会对bitmap进行任何缩放。

  options.inDensity表示的是bitmap所使用的像素密度。如果这个值和options.inTargetDensity不一致,则会对图像进行缩放。 如果被设置成0,则 decodeResource(Resources, int), decodeResource(Resources, int, android.graphics.BitmapFactory.Options), 和decodeResourceStream(Resources, TypedValue, InputStream, Rect, BitmapFactory.Options)将用屏幕密度值来设定这个参数,其它函数将不进行缩放。


防止内存溢出OOM还可以使用以下代码:

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



0 0