最近一段时间致力于android项目开发,期间由于位图引起的java.lang.OutofMemoryError这个错误一直困扰我,所幸最终找到一丝线索,特分享下。
众所周知,android的一个application都有自己的一个java虚拟机,这个虚拟机能够使用的最大堆栈可能是16M、24M或者以后出现的48M,但是对于当前应用程序的用户来讲,程序本身的功能已经不再是重中之重,相对应的,程序界面的美观程度已经悄悄的占了很大的比例。UI需求的增大,避免不了图片的处理,自然而然的,一个界面上图片数量的增多,图片大小的增大,就成了开发人员的一个头痛的问题,稍不注意,就出现OutofMemoryError的错误。
处理OutofMemoryError问题首先需要明确一点就是,加载图片到界面,必定需要消耗内存,我们要做的就是尽量减少这个内存消耗以及及时的回收当前不需要开销的内存。首先,我们讨论下及时回收当前不需要开销的内存,这个大家都知道,android有自己的内存回收机制,但是这个回收机制并不是万能滴,比如现在的内存消耗已经达到了20M,这个时候我们需要创建一个5M的Bitmap类型的临时变量,这个时候必然会出现内存溢出的情况,所以我们在需要的时候,自己手动调用回收接口,回收内存中不需要的部分;当然,强引用、bitmap等一些内存回收器不能回收的,也需要我们自己去释放。
其次,我们讲下这个减少内存消耗的问题。这个其实很简单,就是缩小位图,因为我从UI小组取得的图片达到了1000*1600尺寸的图片,这个对于手机分辨率来讲,还是相对太大了。因此,我们需要对图片进行瘦身,瘦身的关键还是在Options这个类上,
public static void RecycleBitmap(ImageView imgv)
{
Drawable toRecycle = imgv.getDrawable();
if (null != toRecycle && toRecycle instanceof BitmapDrawable) {
Bitmap bitmapRecycle = ((BitmapDrawable)toRecycle).getBitmap();
if (null != bitmapRecycle && !bitmapRecycle.isRecycled()) {
bitmapRecycle.recycle();
}
}
imgv.setImageBitmap(null);
}
public static void setImageURI(ImageView imgv, Uri uri, int nWidth, int nHeight)
{
try {
RecycleBitmap(imgv);
System.gc();
System.runFinalization();
Options opts = new Options();
opts.inJustDecodeBounds = true;
BitmapFactory.decodeFile(uri.getPath(), opts);
int xScale = opts.outWidth / nWidth;
int yScale = opts.outHeight / nHeight;
opts.inSampleSize = xScale>yScale ? xScale : yScale;
opts.inJustDecodeBounds = false;
Bitmap bm = BitmapFactory.decodeFile(uri.getPath(), opts);
imgv.setImageBitmap(bm);
//imgv.setImageURI(uri);
System.gc();
}
catch (OutOfMemoryError e) {
System.gc();
System.runFinalization();
}
}
这个是我用的一个接口,调用setImageURI,参数说明如下
ImageView imgv:要设置内容的控件
Uri uri:要设置的图片URI
int nWidth:控件的宽度
int nHeight:控件的高度
经过我们小组的测试,嘿嘿,确实减少了内存的开销,目前正在进行压力测试以及分析其中缘由,后续应该有相应的文档。