【Android】Bitmap的管理
与图片有关的软件免不了要做Bitmap的管理,要不然很可能就会发生OutOfMemory(OOM)的错误,致使程序崩溃。引起这种现象的原因无非是:
1.长期保持对某个对象或数据的引用,导致java的垃圾回收器不能回收不再使用的内存空间;
2.正在使用的有效对象占用内存空间大,导致多个有效对象生成时,吃完程序所分配的内存;
一般会报这种错误:java.lang.OutOfMemoryError: bitmap size exceeds VM budget,这是因为,android系统中读取位图Bitmap时.分给虚拟机中图片的堆栈大小只有8M。所以不管是如何调用的图片,太多太大虚拟机肯定会报这个错误。(对于实际的机器来说,这个内存分配是不是很大?)
而像相册这样子的应用,最好的效果是:
1)将图片(单个资源)缩小到适当的大小,以便于同时加载多张图片;
2)就算缩小到适当的大小,我们也不能将所有图片的引用同时保存在内存中,这时候需要将部分的图片释放;
遇到这种问题的解决方案是:缩小图片+回收资源的方式,来优化内存:
尽量不要使用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中配置相应的图片资源,否则在不同分辨率机器上都是同样大小(像素点数量),显示出来的大小就不对了。
1)缩小图片的方式:
1 InputStream is = this.getResources().openRawResource(R.drawable.pic1); 2 BitmapFactory.Options options=new BitmapFactory.Options(); 3 options.inJustDecodeBounds = false; 4 options.inSampleSize = 10; //width,hight设为原来的十分一 5 Bitmap btp =BitmapFactory.decodeStream(is,null,options);
2)回收图片的方式:
1 if(!bmp.isRecycle() ){ 2 bmp.recycle() //回收图片所占的内存 3 system.gc() //提醒系统及时回收 4 }
缓存:加载图片的时候首先检测是否被缓存然后再去动作
1 //用来存放图片的缓存 2 HashMap<Integer, Bitmap> bitmapCache = new HashMap<Integer, Bitmap>(); 3 //如果没有图片,或者已经存在 4 if(bitmapCache.isEmpty() || !AppConst.bitmapCache.containsKey(position)){ 5 bitmapCache.put(position, bm); 6 System.out.println("-----------inset cache---------"); 7 }
定义FreeBitmap函数,在activity结束的时候,调用FreeBitmap函数,回收map中的资源
1 private void FreeBitmap(HashMap<Integer, Bitmap> cache){ 2 if(cache.isEmpty()){ 3 return; 4 } 5 for(Bitmap bitmap:cache.values()){ 6 if(bitmap != null && !bitmap.isRecycled()){ 7 bitmap.recycle(); 8 System.out.println("=============recycle bitmap======="); 9 } 10 } 11 cache.clear(); 12 }