概述
今天朋友使用Universal-Image-Loader的ImageLoader加载图片时遇到oom的问题,然后我按照网上的方法试了下,都没作用。最后不得不自己定位解决……
问题描述
用一个gridview显示网络图片
GridView可以下拉刷新(更新最新的20条),上拉加载(加载20条);
当显示100张左右图片的时候,log就会打印出oom异常。
最后定位到是:position相同,但getView()会触发多次(相信很多人都遇到过)。而position相同,获取到网络上图片的bitmap却不是同一对象
加载图片的代码片段
/*
*imageUrl 图片地址
*imageView 放图片的ImageView实例
*options 第三方框架的DisplayImageOptions
*SimpleImageLoadingListener 图片加载的监听
*/
ImageLoader.getInstance().displayImage(imageUrl, imageView, options, new SimpleImageLoadingListener() {
@Override
public void onLoadingStarted(String imageUri, View view) {
}
@Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
}
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
//getView()调用多次,position相同,但返回的loadedImage对象却是多个实例。
}
});
打印的log
01-29 09:11:26.760 ---> android.graphics.Bitmap@2f414b76;position=1
01-29 09:11:26.830 ---> android.graphics.Bitmap@3057b014;position=0
01-29 09:11:26.830 ---> android.graphics.Bitmap@107440bd;position=3
01-29 09:11:26.890 ---> android.graphics.Bitmap@21702bfe;position=6
01-29 09:11:26.950 ---> android.graphics.Bitmap@1810edac;position=9
01-29 09:11:26.950 ---> android.graphics.Bitmap@26a7ca75;position=0
01-29 09:11:26.960 ---> android.graphics.Bitmap@209f0a0a;position=8
01-29 09:11:26.960 ---> android.graphics.Bitmap@2682827b;position=7
01-29 09:11:27.000 ---> android.graphics.Bitmap@caccb57;position=0
01-29 09:11:27.000 ---> android.graphics.Bitmap@27d14644;position=5
01-29 09:11:27.000 ---> android.graphics.Bitmap@141bd32d;position=4
01-29 09:11:27.050 ---> android.graphics.Bitmap@2abe82b0;position=2
01-29 09:11:27.050 ---> android.graphics.Bitmap@30f7529;position=0
01-29 09:11:27.110 ---> android.graphics.Bitmap@179fce4f;position=0
01-29 09:13:05.350 ---> android.graphics.Bitmap@1a5536a4;position=12
01-29 09:13:05.350 ---> android.graphics.Bitmap@13c66c0d;position=0
01-29 09:13:05.350 ---> android.graphics.Bitmap@3f7627c2;position=15
01-29 09:13:05.350 ---> android.graphics.Bitmap@77839d3;position=13
01-29 09:13:05.420 ---> android.graphics.Bitmap@1874ed1a;position=18
01-29 09:13:05.420 ---> android.graphics.Bitmap@623104b;position=19
01-29 09:13:05.420 ---> android.graphics.Bitmap@30e6fa28;position=16
01-29 09:13:05.420 ---> android.graphics.Bitmap@1580e341;position=17
01-29 09:13:05.420 ---> android.graphics.Bitmap@3264c0e6;position=14
01-29 09:13:05.420 ---> android.graphics.Bitmap@3f906627;position=11
01-29 09:13:05.420 ---> android.graphics.Bitmap@38c590d4;position=10
01-29 09:13:05.420 ---> android.graphics.Bitmap@3637727d;position=9
01-29 09:13:05.420 ---> android.graphics.Bitmap@42c0572;position=8
01-29 09:13:05.420 ---> android.graphics.Bitmap@18933dc3;position=0
01-29 09:13:05.420 ---> android.graphics.Bitmap@1b54e640;position=3
01-29 09:13:05.420 ---> android.graphics.Bitmap@16cdb979;position=7
01-29 09:13:05.480 ---> android.graphics.Bitmap@ce13d58;position=0
01-29 09:13:05.480 ---> android.graphics.Bitmap@26a81eb1;position=4
01-29 09:13:05.480 ---> android.graphics.Bitmap@1cd52f96;position=5
01-29 09:13:05.480 ---> android.graphics.Bitmap@1f492717;position=6
01-29 09:13:05.480 ---> android.graphics.Bitmap@2ed8d704;position=2
01-29 09:13:05.480 ---> android.graphics.Bitmap@14eef4ed;position=1
解决方案
gridview->adapter->getView()->使用框架bitmap优化代码片段
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
addRecycleBitmap(position,loadedImage);//复用bitmap对象
}
addRecycleBitmap()方法代码
private HashMap<Integer,Bitmap> recycleBitmaps = new private HashMap<Integer,Bitmap>();
Bitmap localBitmap= null;
/**
*将不再使用的bitmap recycle掉
*/
public void addRecycleBitmap(int position,Bitmap bitmap) {
//注意这里不能优化position=0的,否则不显示第一个。原因还要再仔细瞅瞅
if(recycleBitmaps.containsKey(position)&&position!=0){//第1位已经有bitmap了
localBitmap = recycleBitmaps.get(position);
if(null != localBitmap&&localBitmap != bitmap&&!localBitmap.isRecycled()){
localBitmap.recycle();
localBitmap = null;
}
}
recycleBitmaps.put(position,bitmap);
}
到此,就能解决掉这个问题了。当然代码方面还可以优化,只是说这个问题的解决方案是这样的……只是还有几点疑惑
疑惑
- 为什么getView()的position=0,bitmap没法recycle
- 同一个position=0为什么执行了多次(知道是因为重新绘制了界面,但是具体代码源码没浏览到)
- bitmap所在的activity销毁了,bitmap对象被回收了?
- 如果图片不停的增加,到1000张甚至更多,这肯定会撑爆。所以最终解决方案就是类似getView的复用
网上一些关于解决ImageLoader OOM的建议
参考博客
1. 减少线程池中线程的个数,在ImageLoaderConfiguration中的(.threadPoolSize)中配置,推荐配置1-5
2. 在DisplayImageOptions选项中配置bitmapConfig为Bitmap.Config.RGB_565,因为默认是ARGB_8888, 使用RGB_565会比使用ARGB_8888少消耗2倍的内存
3. 在ImageLoaderConfiguration中配置图片的内存缓存为memoryCache(new WeakMemoryCache()) 或者不使用内存缓存
4. 在DisplayImageOptions选项中设置.imageScaleType(ImageScaleType.IN_SAMPLE_INT)或者imageScaleType(ImageScaleType.EXACTLY)