您的位置:首页 > 移动开发 > Android开发

Android加载大图片OOM异常解决

2012-07-05 15:35 555 查看
项目用到加载大图片,app老是出现OOM异常,总结了几点经验,供参考。

1、手动干涉dalvik的堆内存处理效率:

private final static float TARGET_HEAP_UTILIZATION = 0.75f;
//for same activity
public void onCreate()
{
…………
VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION);
…………
}


2、手动指定Android堆大小:

private final static int CWJ_HEAP_SIZE = 6* 1024* 1024 ;
//for same activity
public void onCreate()
{
…………
VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE); //设置最小heap内存为6MB大小。当然对于内存吃紧来说还可以通过手动干涉GC去处理
…………
}


3、手动指定回收内存,指定gc:

if(bitmap!=null && !bitmap.isRecycled())
{
bitmap.recycle();
System.gc();
}


4、图片必须进行缩放,不然多半会出OOM:

/**
* @param url
*            图片的url
* @param sc
*            ,显示的像素大小
* @return 返回指定RUL的缩略图
*
* @author jevan 2012-7-3
*
*/
public static Bitmap loadImageFromUrl(String url, int sc)
{

URL m;
InputStream i = null;
BufferedInputStream bis = null;
ByteArrayOutputStream out = null;

if (url == null)
return null;
try
{
m = new URL(url);
i = (InputStream) m.getContent();
bis = new BufferedInputStream(i, 1024 * 4);
out = new ByteArrayOutputStream();
int len = 0;

while ((len = bis.read(isBuffer)) != -1)
{
out.write(isBuffer, 0, len);
}
out.close();
bis.close();
} catch (MalformedURLException e1)
{
e1.printStackTrace();
return null;
} catch (IOException e)
{
e.printStackTrace();
}
if (out == null)
return null;
byte[] data = out.toByteArray();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(data, 0, data.length, options);
options.inJustDecodeBounds = false;
int be = (int) (options.outHeight / (float) sc);
if (be <= 0)
{
be = 1;
} else if (be > 3)
{
be = 3;
}
options.inSampleSize = be;
Bitmap bmp =null;
try
{
bmp = BitmapFactory.decodeByteArray(data, 0, data.length, options); //返回缩略图
} catch (OutOfMemoryError e)
{
// TODO: handle exception
MainActivity.print("Tile Loader (241) Out Of Memory Error " + e.getLocalizedMessage());

System.gc();
bmp =null;
}
return bmp;
}


把上面几条全部用上,OOM的异常基本上能完全避免!!!

以下内容为转载,收藏。

//我们在BitmapManager.instance().decodeFile对图片进行解码,生成Bitmap的时候,我们会发现很多大图片会报OutOfMemoryError的错误,这个时候我们需要改变options里面的一些参数来解决这个问题,不然我们程序就跑不下去了。最简单的方法就是改变options.inSampleSize这个参数,把它增大,就可以解决很多图片OutOfMemoryError的问题。
//下面是一个使用了这个方式的代码
public static Bitmap makeBitmap(String path, int minSideLength, int maxNumOfPixels, BitmapFactory.Options options)
{
Bitmap b = null;
Log.i(TAG, "makeBitmap : path = " + path);
if (path == null)
return null;
File f = new File(path);

//try {
// b = BitmapManager.instance().decodeFile(f, null);
//} catch (OutOfMemoryError ex) {
// Log.e(TAG, "Got oom exception, we may try one more time, using Options:" + ex.getMessage());
if (options == null)
{
options = new BitmapFactory.Options();
}

try
{
options.inJustDecodeBounds = true;
BitmapManager.instance().decodeFile(f, options);
if (options.mCancel || options.outWidth == -1 || options.outHeight == -1)
{
return null;
}
options.inSampleSize = computeSampleSize(options, minSideLength, maxNumOfPixels);
options.inJustDecodeBounds = false;
options.inDither = true;
options.inPreferredConfig = null;//Bitmap.Config.ARGB_8888;

b = BitmapManager.instance().decodeFile(f, options);
} catch (OutOfMemoryError ex2)
{
Log.e(TAG, "Got oom exception when retry the 2nd time,options.inSampleSize= " + options.inSampleSize + " minSideLength = "
+ minSideLength + " maxNumOfPixels =" + maxNumOfPixels, ex2);
try
{
options.inSampleSize += 1;
options.inJustDecodeBounds = false;
options.inDither = true;
options.inPreferredConfig = null;
b = BitmapManager.instance().decodeFile(f, options);
} catch (OutOfMemoryError e)
{
Log.e(TAG, "Got oom exception when retry the 2nd time,options.inSampleSize= " + options.inSampleSize + " minSideLength = "
+ minSideLength + " maxNumOfPixels =" + maxNumOfPixels, e);
try
{
options.inSampleSize += 1;
options.inJustDecodeBounds = false;
options.inDither = true;
options.inPreferredConfig = null;
b = BitmapManager.instance().decodeFile(f, options);
} catch (OutOfMemoryError ex)
{
Log.e(TAG, "Got oom exception when retry the 2nd time,options.inSampleSize= " + options.inSampleSize
+ " minSideLength = " + minSideLength + " maxNumOfPixels =" + maxNumOfPixels, ex);
return null;
}
}
}

//}
return b;
}


//另外一处代码
public static Bitmap getBitpMap(InputStream is)
{
ParcelFileDescriptor pfd;
try
{
pfd = getContentResolver().openFileDescriptor(uri, "r");
} catch (IOException ex)
{
return null;
}
java.io.FileDescriptor fd = pfd.getFileDescriptor();
BitmapFactory.Options options = new BitmapFactory.Options();
//先指定原始大小
options.inSampleSize = 1;
//只进行大小判断
options.inJustDecodeBounds = true;
//调用此方法得到options得到图片的大小
BitmapFactory.decodeFileDescriptor(fd, null, options);
//BitmapFactory.decodeStream(is, null, options);
//我们的目标是在800pixel的画面上显示。
//所以需要调用computeSampleSize得到图片缩放的比例
options.inSampleSize = computeSampleSize(options, 800);
//OK,我们得到了缩放的比例,现在开始正式读入BitMap数据
options.inJustDecodeBounds = false;
options.inDither = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;

//根据options参数,减少所需要的内存
//        Bitmap sourceBitmap = BitmapFactory.decodeFileDescriptor(fd, null, options);
Bitmap sourceBitmap = BitmapFactory.decodeStream(is, null, options);
return sourceBitmap;
}

//这个函数会对图片的大小进行判断,并得到合适的缩放比例,比如2即1/2,3即1/3
static int computeSampleSize(BitmapFactory.Options options, int target)
{
int w = options.outWidth;
int h = options.outHeight;
int candidateW = w / target;
int candidateH = h / target;
int candidate = Math.max(candidateW, candidateH);
if (candidate == 0)
return 1;
if (candidate > 1)
{
if ((w > target) && (w / candidate) < target)
candidate -= 1;
}
if (candidate > 1)
{
if ((h > target) && (h / candidate) < target)
candidate -= 1;
}
//if (VERBOSE)
Log.v(TAG, "for w/h " + w + "/" + h + " returning " + candidate + "(" + (w / candidate) + " / " + (h / candidate));
return candidate;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: