Android:解决“Bitmap Size Exceeds VM Budget”错误

我发现开发Android应用时最普遍的错误是“java.lang.OutOfMemoryError: Bitmap Size Exceeds VM Budget”。当Activity使用大量的位图(Bitmap),屏幕方向改变后就会频繁出现这个错误。因为Activity被销毁,然后重新创建,布局从XML文件加载,这个过程消耗了虚拟机为Bitmap分配的可用内存。
由于位图对Activity有交叉引用,在先前的Activity布局中,位图没有被垃圾回收器适当释放。经过诸多经验,我发现一个好的方法可以解决此问题。

首先,在你的XML布局的父视图设置id属性:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:id="@+id/RootView"
>
...

然后,在你的Activity的onDestroy()方法中,调用unbindDrawable()方法并传递一个父视图引用,之后调用System.gc()方法。

@Override
protected void onDestroy() {
    super.onDestroy();
 
    unbindDrawables(findViewById(R.id.RootView));
    System.gc();
}
 
private void unbindDrawables(View view) {
    if (view.getBackground() != null) {
        view.getBackground().setCallback(null);
    }
    if (view instanceof ViewGroup) {
        for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
            unbindDrawables(((ViewGroup) view).getChildAt(i));
        }
        ((ViewGroup) view).removeAllViews();
    }
}

unbindDrawable()方法会递归浏览视图树,并且:
•在所有背景图片中移除回调接口
•在每个ViewGroup中移除对应的子视图
这解决了我们的Mobialia应用中许多问题。
2011-03-30更新:
今天来自partanBits的@luiskap告诉我另一个好方法。如果你不需要不同的布局去适应横竖屏,你可以让你的Activity在屏幕方向改变时作出相应的反应:在Manifest文件中添加android:configChanges="keyboardHidden|orientation",重写onConfigurationChanged方法,调用setContentView重用已经创建的视图。StackOverflow有一个很好例子。


原文链接:Dealing with the “Bitmap Size Exceeds VM Budget” error

OOM bitmap size exceeds VM budget 处理

03-27

我在从widget 多次进入程序,再退出到桌面,再通过widget进入程序,反复操作,出现如下异常rn 启动activity的代码 rn MailListBindData mailData = ServiceForWidget.getWidgetData()rn .get(curPosition);rn Intent showEmailDetail = new Intent();rn showEmailDetail.setClass(context,rn MailDetailAndDoneActivity.class);rn showEmailDetail.putExtra(MailListActivity.extraKey_ThreadMode,rn false);rn showEmailDetail.putExtra(MailListActivity.extraKey_accountId,rn mailData.getMessageInfo().getAccountId());rn showEmailDetail.putExtra(MailListActivity.extraKey_folderId,rn mailData.getMessageInfo().getFolderId());rnrn showEmailDetail.putExtra(rn MailListActivity.extraKey_groupPosition, curPosition);rn showEmailDetail.putExtra(rn MailListActivity.extraKey_childPosition, 0);rn showEmailDetail.putExtra(MailListActivity.extraKey_editType,rn MailListActivity.EDITTYPE_NONE);rn showEmailDetail.putExtra(MailListActivity.extraKey_objectView,rn Constants.MAIL_DETAIL_VIEW);rnrn showEmailDetail.putExtra("messageInfo",rn mailData.getMessageInfo());rnrn showEmailDetail.putExtra(MailListActivity.extraKey_MailCount,rn ServiceForWidget.getWidgetData().size());rn showEmailDetail.putExtra(Constants.ACTIVITY_NAME_KEY,rn MediumMailWidget.class.getSimpleName());rn showEmailDetailrn .putExtra(rn MailListActivity.extraKey_MailTypeTitle,rn context.getString(R.string.unified_account_receive_folder_name));rn showEmailDetail.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);rn showEmailDetail.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);rnrn context.startActivity(showEmailDetail);rnrnrn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): java.lang.RuntimeException: Unable to start activity ComponentInfocom.nttdocomo.communicase.carriermail/com.nttdocomo.communicase.carriermail.activity.MailListActivity: android.view.InflateException: Binary XML file line #20: Error inflating class rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1654)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1670)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.app.ActivityThread.access$1500(ActivityThread.java:117)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.os.Handler.dispatchMessage(Handler.java:99)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.os.Looper.loop(Looper.java:123)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.app.ActivityThread.main(ActivityThread.java:3695)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at java.lang.reflect.Method.invokeNative(Native Method)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at java.lang.reflect.Method.invoke(Method.java:507)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:842)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at dalvik.system.NativeStart.main(Native Method)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): Caused by: android.view.InflateException: Binary XML file line #20: Error inflating class rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.view.LayoutInflater.createView(LayoutInflater.java:518)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:568)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.view.LayoutInflater.rInflate(LayoutInflater.java:623)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.view.LayoutInflater.rInflate(LayoutInflater.java:626)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.view.LayoutInflater.rInflate(LayoutInflater.java:626)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.view.LayoutInflater.inflate(LayoutInflater.java:408)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.view.LayoutInflater.inflate(LayoutInflater.java:320)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.view.LayoutInflater.inflate(LayoutInflater.java:276)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at com.nttdocomo.communicase.carriermail.factory.MailListViewFactory.initMailTitleBarView(MailListViewFactory.java:1585)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at com.nttdocomo.communicase.carriermail.factory.MailListViewFactory.createBlockFolderView(MailListViewFactory.java:1432)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at com.nttdocomo.communicase.carriermail.factory.MailListViewFactory.createMailListView(MailListViewFactory.java:259)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at com.nttdocomo.communicase.carriermail.activity.MailListActivity.createListView(MailListActivity.java:670)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at com.nttdocomo.communicase.carriermail.activity.MailListActivity.onCreate(MailListActivity.java:790)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1618)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): ... 11 morern03-27 18:35:30.540: ERROR/AndroidRuntime(29243): Caused by: java.lang.reflect.InvocationTargetExceptionrn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at java.lang.reflect.Constructor.constructNative(Native Method)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at java.lang.reflect.Constructor.newInstance(Constructor.java:415)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.view.LayoutInflater.createView(LayoutInflater.java:505)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): ... 26 morern03-27 18:35:30.540: ERROR/AndroidRuntime(29243): Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budgetrn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.graphics.Bitmap.nativeCreate(Native Method)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.graphics.Bitmap.createBitmap(Bitmap.java:477)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.graphics.Bitmap.createBitmap(Bitmap.java:444)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:349)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.graphics.BitmapFactory.finishDecode(BitmapFactory.java:498)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:473)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:336)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.content.res.Resources.loadDrawable(Resources.java:1709)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.content.res.TypedArray.getDrawable(TypedArray.java:601)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.view.View.(View.java:1951)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.widget.ImageView.(ImageView.java:112)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.widget.ImageButton.(ImageButton.java:85)rn03-27 18:35:30.540: ERROR/AndroidRuntime(29243): at android.widget.ImageButton.(ImageButton.java:81)rn

救命啊!图片内存泄露java.lang.OutOfMemoryError:bitmap size exceeds VM budget

08-25

private void drawEnergyLine(Canvas canvas, int min, int max, Bitmap bmp,rn int type) rn int bmpWidth = bmp.getWidth();rn int bmpHeight = bmp.getHeight();rn // 设置缩小比例rn double scale = (float) min / (float) max;rn // 计算出这次要缩小的比例rn float scaleWidth = 1;rn float scaleHeight = 1;rn scaleWidth = (float) (scaleWidth * scale);rn scaleHeight = (float) (1);rn // 产生resize后的Bitmap对象rn Matrix matrix = new Matrix();rn matrix.postScale(scaleWidth, scaleHeight);rn Bitmap resizeBmp = Bitmap.createBitmap(bmp, 0, 0, bmpWidth, bmpHeight,rn matrix, true);rn switch (type) rn case 0:rn canvas.drawBitmap(resizeBmp, 10, 120, mPaint);// blood show 1rn break;rn case 1:rn canvas.drawBitmap(resizeBmp, 690, 120, mPaint);// blood show 2rn break;rn case 2:rn canvas.drawBitmap(resizeBmp, 10, 358, mPaint);// 黄能量小长条rn break;rn default:rn break;rn rn //resizeBmp.recycle();//这两句我添加了就画面就不能点了,所以不知道该如何释放rn //System.gc();rn rn////////////////////////////////rn我在draw(canvas)//draw里调用这个函数rnprivate void drawEnergyLine(Canvas canvas, 1, 5,bmp1,rn 0);//类似这样的调用rnrn在后面的线程中rnrun()rnwhile(true)rntryrndraw();rnsleep(200);rncatch(Exception ex)rnrn//提示的错误为:rn2496-byte external allocation too large for this processrnVM won't let us allocate 2496 bytesrnjava.lang.OutOfMemoryError:bitmap size exceeds VM budgetrn....图片内存如何释放,这个问题冒似提的人很多啊,可是到底原理是什么呢,我怎么知道一个图片不用了呢,说不定满足啥条件了又用了呢?

没有更多推荐了,返回首页

私密
私密原因:
请选择设置私密原因
  • 广告
  • 抄袭
  • 版权
  • 政治
  • 色情
  • 无意义
  • 其他
其他原因:
120
出错啦
系统繁忙,请稍后再试