赞
踩
下面这些都是我在做各个app时总结出来的,希望对各位有用:
public static int computeSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) { int initialSize = computeInitialSampleSize(options, minSideLength,maxNumOfPixels); int roundedSize; if (initialSize <= 8 ) { roundedSize = 1; while (roundedSize < initialSize) { roundedSize <<= 1; } } else { roundedSize = (initialSize + 7) / 8 * 8; } return roundedSize; } private static int computeInitialSampleSize(BitmapFactory.Options options,int minSideLength, int maxNumOfPixels) { double w = options.outWidth; double h = options.outHeight; int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels)); int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(Math.floor(w / minSideLength), Math.floor(h / minSideLength)); if (upperBound < lowerBound) { // return the larger one when there is no overlapping zone. return lowerBound; } if ((maxNumOfPixels == -1) && (minSideLength == -1)) { return 1; } else if (minSideLength == -1) { return lowerBound; } else { return upperBound; } }
BitmapFactory.Options opts = new BitmapFactory.Options(); opts.inJustDecodeBounds = true; BitmapFactory.decodeFile(imageFile, opts); opts.inSampleSize = computeSampleSize(opts, -1, 128*128); opts.inJustDecodeBounds = false; try { Bitmap bmp = BitmapFactory.decodeFile(imageFile, opts); imageView.setImageBitmap(bmp); } catch (OutOfMemoryError err) { }
大部分的app都是使用ListView来展示图片的,其实ListView的adapter是可以重用每个list的view的:
@Override public View getView(int position, View convertView, ViewGroup parent) { Log.e("ok", "position:"+position); if (convertView == null) { // 这句就是重用的关键 convertView = LayoutInflater.from(context).inflate(R.layout.xxx, null); } }
重用convertView的方式也是google推荐的,这样系统是可以自动回收已经滑出屏幕的资源的。
但是重用convertView会有一个问题,就是如果图片是异步加载的,快速滑动listview时每个list的上的图片会不停的闪(以前做省电宝的时候遇到过这个bug),这个bug是由于我没有判断ImageView控件是否是重用的而引起的。 要解决这个bug,只需在异步加载图片的时候根据每个ImageView的tag判断一下ImageView是否重用:
boolean imageViewReused(ImageView iv, URL url) { String tag=imageViewsHashMap.get(iv); // imageViewsHashMap是用来存储ImageView和tag的对应关系的(我是用图片的url来标识的tag,这个tag可以随意取值,只要能唯一的标识这个ImageView就好了) if(tag==null || !tag.equals(url)) { return true; } return false; }
如果ImageView是重用的,就先设置一张默认的图片,等异步加载完成后再设置成最终要展示的图片。 如果ImageView不是重用的,忽略。
之前在做壁纸的时候一直出现OOM的问题,找了好久都没有发现是怎么回事,之前做市场的时候也有遇到过,而且我确定我在使用了所有的Bitmap以后都手动释放了那些资源。这是一个很奇怪的事情,虽然我现在解了这个bug了,但是有些android的机制我还不是很理解,也希望有大拿指导一下。
下面是解决方案:
ImageView是存储在JVM里面的,但是Bitmap是存储在native heap里面的(3.0之前的系统是这样的),壁纸有一个大图浏览界面(一个Activity),每次进入这个界面的时候都会加载一张大图(大概在70K-200K),我加载大图的代码:
imageView.setImageBitmap(bitmap); //
我在每次Activity退出时都会主动的回收掉这个bitmap,代码:
if(bitmap != null && !bitmap.isrecycle) { bitmap.recycle(); // 主动释放以后系统再GC也不管用,不知道为什么,我也尝试过对bitmap使用软引用/弱应用等,也都是不起作用 }
我在DDMS里面看到系统也会执行GC,但是就是不会回收我释放的这些资源,多次(一般3-5次)进入大图浏览界面以后一般就会报OOM的错误了。
后来我把退出时的代码改成了下面的形式:
imageView.setImageBitmap(null); // 不是主动的回收bitmap,而是主动的释放对bitmap的引用 imageView = null;
我从DDMS里面看到资源基本都被回收了,壁纸也基本不会再报OOM的错误了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。