读书人

Android开发中处置图片OOM的若干方法小

发布时间: 2012-11-16 14:12:14 作者: rapoo

Android开发中处理图片OOM的若干方法小结

?

演示结果与说明

1.演示一

首先采用最简单的图片加载方式,不带任何图片缓存、调整大小或者回收,SimpleImageLoader.class便是承担此职责。加载图片部分的代码如下:

@Override

public Bitmap loadBitmapImage(String path) {

?????? return BitmapFactory.decodeFile(path);

}

@Override

public Drawable loadDrawableImage(String path) {

?????? return new BitmapDrawable(path);

}

演示结果:在模拟器上图片只能加载1-3张,之后便会出现OOM错误;在Defy上不会出现错误;原因是两者内存限制不同,Defy上运行的是第三方ROM,内存分配有40MB。另外gallery每次显示一张图片时,都要重新解析获得一张图片,尽管在Defy上还未曾出错,但当图片量加大,GC回收不及时时,还是有可能出现OOM。

2.演示二

为图片加载的添加一个软引用缓存,每次图片从缓存中获取图片对象,若缓存中不存在,才会从Sdcard加载图片,并将该对象加入缓存。同时软引用的对象也有助于GC在内存不足的时候回收它们。ImageLoaderWithCache.class负责这个职责,关键代码如下:

private HashMap<String, SoftReference<Bitmap>> mImageCache;

?????? @Override

?????? public Bitmap loadBitmapImage(String path) {

?????? ?????? if(mImageCache.containsKey(path)) {

?????? ?????? ?????? SoftReference<Bitmap> softReference = mImageCache.get(path);

?????? ?????? ?????? Bitmap bitmap = softReference.get();

?????? ?????? ?????? if(null != bitmap)

?????? ?????? ?????? ?????? return bitmap;

?????? ?????? }

?????? ?????? Bitmap bitmap = BitmapFactory.decodeFile(path);

?????? ?????? mImageCache.put(path, new SoftReference<Bitmap>(bitmap));

?????? ?????? return bitmap;

?????? }

?????? @Override

?????? public Drawable loadDrawableImage(String path) {

?????? ?????? return new BitmapDrawable(loadBitmapImage(path));

?????? }

演示结果:在模拟器上,能不无缓存时多加载1-2张图片,但还是会出现OOM;在Defy上不曾出错。由于本次所用的图片都相对比较占内存,在GC还未来得及回收软引用对象时,就又要申请超出剩余量的内存空间,因此仍然没能完全避免OOM。如果换成加载大量的小图片,比如100*100规格的,缓存中软引用的作用可能就发挥出来了。(这一假设可以进一步试验证明一下)

3.演示三

为了进一步避免OOM,除了缓存,还可以对图片进行压缩,进一步节省内存,多数情况下调整图片大小并不会影响应用的表现力。ImageLoaderWithScale.class便是负责这个职责,调整大小的代码如下:

BitmapFactory.Options options = new BitmapFactory.Options();

?????? options.inJustDecodeBounds = true;

?????? BitmapFactory.decodeFile(path, options);

?????? if (options.mCancel || options.outWidth == -1 || options.outHeight == -1) {

?????? ?????? Log.d(“OomDemo”, “alert!!!” + String.valueOf(options.mCancel) + ” ” + options.outWidth + options.outHeight);

?????? ?????? return null;

?????? }

?????? options.inSampleSize = Util.computeSampleSize(options, 600, (int) (1 * 1024 * 1024));

?????? Log.d(“OomDemo”, “inSampleSize: ” + options.inSampleSize);

?????? options.inJustDecodeBounds = false;

?????? options.inDither = false;

?????? options.inPreferredConfig = Bitmap.Config.ARGB_8888;

?????? Bitmap bitmap = BitmapFactory.decodeFile(path, options);

演示结果:在上述代码中,首先解码图片的边界,在不需要得到Bitmap对象的前提下就能获得图像宽高(宽高值分别被设置到options.outWidth和options.outHeight两个属性中)。computeSampleSize这个方法的参数分别为“解析图片所需的BitmapFactory.Options”、“调整后图片最小的宽或高值”、“调整后图片的内存占用量上限”。结合原始图片的宽高,此方法可以计算得到一个调整比例,再用此比例调整原始图片并加载到内存中,此时图片所消耗的内存不会超出事先指定的大小。在模拟器中,限制图片所占内存大小为1*1024*1024时,比未压缩过时能加载更多图片,但仍然会出现OOM;若限制图片所占内存大小为0.5*1024*1024,则能完整的载入所有图片。所以调整图片大小还是能够有效节省内存的。在Defy中不会出错,原因同上。

4.演示四

在有些情况下,严重缩小图片还是会影响应用的显示效果的,所以有必要在尽可能少地缩小图片的前提下展示图片,此时手动去回收图片就变得尤为重要。在类ImageLoaderWithRecyle.class中,便增加了回收图片资源的方法:

@Override

?????? public void releaseImage(String path) {

?????? ?????? if(mImageCache.containsKey(path)) {

?????? ?????? ?????? SoftReference<Bitmap> reference = mImageCache.get(path);

?????? ?????? ?????? Bitmap bitmap = reference.get();

?????? ?????? ?????? if(null != bitmap) {

?????? ?????? ?????? ?????? Log.d(“OomDemo”, “recyling ” + path);

?????? ?????? ?????? ?????? bitmap.recycle();

?????? ?????? ?????? }

?????? ?????? ?????? mImageCache.remove(path);

?????? ?????? }

?????? }

演示结果:图片压缩限制仍然维持在1*1024*1024,在adapter中,及时调用releaseImage方法,回收暂时不需要的图片。此时模拟器中也从未出现过OOM,所以总的来讲,综合缓存、调整大小、回收等各种手段,还是能够有效避免OOM的。

小结

本文介绍了软引用缓存、调整大小、回收等手段来避免OOM,总体来说效果还是明显的。但实际应用场景中,图片的应用不想本文所演示的那样简单,有时候图片资源可能来自与网络,这时需要配合异步加载的方式先下载图片并通过回调的方法来显示;有时候图片资源还需要加边框、加文字等额外修饰,所以在图片加载之后还要另做处理。

另外由于本人能力所限以及时间关系,本文还有诸多不完善之处。比如对Android内存分配的理解不深,没能透彻地解释Bitmap的内存占用情况;通过自定义堆内存分配大小,优化Dalvik虚拟机的堆内存分配的方法来解决OOM,本文也没有给予演示;再比如在上文的演示试验里,没有把内存占用情况的详细信息用图像形式直观地展示出来;还有演示所用的图片数量过少、规格单一、测试环境偏少,所有没能进行更加严谨科学的对比试验,遗漏了某些意外情况。最后欢迎大家来共同探索、交流并提出建议。

参考代码

http://longerian.googlecode.com/svn/trunk/OomDemo

补充说明

本文原本是发表在本人的原生Wordpress空间里,无奈在天朝无法访问,所以特地搬家到此。

本文参考过的文章资料汇总

http://winuxxan.blog.51cto.com/2779763/512180

http://www.7dot9.com/2010/08/android-bitmap%E5%86%85%E5%AD%98%E9%99%90%E5%88%B6/

http://blog.csdn.net/rickleaf/article/details/6393185

http://hi.baidu.com/455611934/blog/item/cb56aa442bc7b829879473d8.html

http://ck19860613.iteye.com/blog/842732

http://blog.csdn.net/kavendb/article/details/5935577

?

读书人网 >Android

热点推荐