Android ImageView中我们在使用Bitmap加载图片时特别容易造成OOM内存溢出泄露的问题,特别是在像ListView或者RecyclerView这样的控件中大量加载图片,Bitmap内存溢出就更加明显了。
网上有各种说法说可以使用Java虚拟机的垃圾回收器来手动回收Bitmap对象内存,代码类似如下这样:
if(headBitmap != null && !headBitmap.isRecycled()){ headBitmap.recycle(); headBitmap = null; } System.gc();
其实这些方法并不能真的回收bitmap内存,反而内存依然会不断增加,造成OOM内存溢出问题,甚至如果你在别的界面复用了这个图片,就会造成如下这样的问题,导致程序闪退:
Canvas: trying to use a recycled bitmap
所以我们在使用本地图片生成Bitmap对象的时候,要尽量避免bitmap对象造成的OOM现象,可以直接使用如下方法生成一个Bitmap对象,就可以完全避免内存OOM了,代码如下:
/** * 使用SD卡上的图片 */ public Bitmap useTheImage(String imageUrl) { File file = new File(imageUrl); if (!file.exists()) { return null; } BitmapFactory.Options bfOptions = new BitmapFactory.Options(); bfOptions.inDither = false; bfOptions.inPurgeable = true; bfOptions.inInputShareable = true; bfOptions.inTempStorage = new byte[16 * 1024]; bfOptions.inPreferredConfig = Bitmap.Config.RGB_565; bfOptions.outWidth = 130; bfOptions.outHeight = 210; FileInputStream fs = null; try { fs = new FileInputStream(file); if (fs != null) return BitmapFactory.decodeStream(fs, null, bfOptions); } catch (IOException e) { e.printStackTrace(); } finally { if (fs != null) { try { fs.close(); } catch (IOException e) { e.printStackTrace(); } } } return null; }
以上的代码,最主要的是需要使用BitmapFatory中的的decodeStream方法,如下:
decodeStream(@Nullable InputStream is, @Nullable Rect outPadding, @Nullable Options opts)
其中InputStream是文件的字节流
Rect可以为空,不用管
而Options这个参数必须要添加,不然依然会造成Bitmap内存溢出问题的
Bitmap.Config.RGB_565这些参数也能有效的解决Bitmap内存的耗费,因为它是通过降低一点图片的清晰度来节省虚拟机内存,所以建议也用上。
为什么BitmapFactory.decodeStream方法可以避免bitmap内存溢出呢?
因为使用了decodeStream方法之后,处理图片加载就会用本地内存来处理,所以耗费的内存就很小了,也能及时回收掉,所以至今都没有内存泄露的问题。
上面同样的方法,小编使用BitmapFactory的decodeFileDescriptor方法,就会在RecyclerView加载到10多页之后Bitmap就内存泄露了,代码如下:
decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) { validate(opts);
所以小编不建议使用decodeFileDescriptor方法来加载本地图片!