Android 2.3.3中的outofmemory错误:位图大小超过vm预算

12
我知道这个问题已经被问了很多次,但它们都没有明确的解决方案。让我来解释一下这个问题。
  1. 我有一个Activity,每次加载4张图片。
  2. 我在onResume()方法中加载这些图片。
  3. 当加载时,Activity会抛出位图错误。

注意:

  1. 我是使用setImageResource(R.drawable.xxxx)方法设置图片,而不是直接使用位图/Drawable。
  2. 图片已正确缩放。
  3. 该Activity在2.3之前的所有模拟器中都可以正常工作,并且在实际设备(Samsung Galaxy 5)中也可以正常工作。
  4. 错误出现在第一次初始化时,并且没有触发任何方向更改事件。
  5. 每张图片的大小为800 x 600像素,平均大小为15kb。

请告诉我任何解决方案。如果你在Android 2.3.3模拟器中遇到类似的问题,请也告诉我。

[更新] - 稍息片段

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
            ...
    img_topLeft = (ImageView) findViewById(R.id.Img_Alph_Q_TopLeft);
    img_topRight = (ImageView) findViewById(R.id.Img_Alph_Q_TopRight);
    img_bottomLeft = (ImageView) findViewById(R.id.Img_Alph_Q_BottomLeft);
    img_bottomRight = (ImageView) findViewById(R.id.Img_Alph_Q_BottomRight);
   ...
   }
protected void onResume() {
    super.onResume();
            img_topLeft.setImageResource(R.drawable.xxx);
            img_topRight.setImageResource(R.drawable.xxx);
            img_bottomLeft.setImageResource(R.drawable.xxx);
            img_bottomRight.setImageResource(R.drawable.xxx);
   ...
   }
03-21 08:59:17.362: ERROR/dalvikvm-heap(5883): 进程内存不足,无法进行4320000字节的外部分配。 03-21 08:59:17.412: ERROR/GraphicsJNI(5883): 虚拟机不允许我们分配4320000字节 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): 致命异常:java.lang.OutOfMemoryError: bitmap size exceeds VM budget(位图大小超出了VM预算) 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): at android.graphics.Bitmap.nativeCreate(Native Method) 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): at android.graphics.Bitmap.createBitmap(Bitmap.java:477) 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): at android.graphics.Bitmap.createBitmap(Bitmap.java:444) 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:349) 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): at android.graphics.BitmapFactory.finishDecode(BitmapFactory.java:498) 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:473) 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:336) 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697) 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): at android.content.res.Resources.loadDrawable(Resources.java:1709) 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): at android.content.res.Resources.getDrawable(Resources.java:581) 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): at android.widget.ImageView.resolveUri(ImageView.java:501) 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): at android.widget.ImageView.setImageResource(ImageView.java:280) 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): at Quiz.java:124) 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): Quiz.onResume(Quiz.java:92) 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1150) 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): at android.app.Activity.performResume(Activity.java:3832) 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2110) 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2135) 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1668) 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): at android.app.ActivityThread.access$1500(ActivityThread.java:117) 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931) 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): at android.os.Handler.dispatchMessage(Handler.java:99) 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): at android.os.Looper.loop(Looper.java:123) 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): at android.app.ActivityThread.main(ActivityThread.java:3683) 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): at java.lang.reflect.Method.invokeNative(Native Method) 03-21 08:59:17.432: ERROR/AndroidRuntime(5883): at java.lang.reflect.Method.invoke(Method.java
public class BitmapResizer {

public static Bitmap decodeImage(Resources res, int id ,int requiredSize){
    try {
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, id, o);

        //Find the correct scale value. It should be the power of 2.
        final int REQUIRED_SIZE=requiredSize;
        int width_tmp=o.outWidth, height_tmp=o.outHeight;
        int scale=1;
        while(true){
            if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
                break;
            width_tmp/=2;
            height_tmp/=2;
            scale*=2;
        }

        //decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize=scale;
        return BitmapFactory.decodeResource(res, id, o2);
    } catch (Exception e) {

    }
    return null;
}

}

//Class call
int requiredsize = 100; // Still playing around with this number to find the optimum value
img_topLeft.setImageBitmap(BitmapResizer.decodeImage(getResources(),
        AlphResourceSet.R.drawable.xxx, requiredsize));

请发布您的onResume代码,这样可能更容易帮助您。 - Eric Nordvik
3个回答

3

位图会占用大量的内存空间。

在活动中加载所有图像时,不要为每个图像创建一个新的位图变量,而是可以创建一个位图变量并尽可能多地重用它们。

您可以使用此代码片段来调整位图大小:

http://pastebin.com/D8vbQd2u


我需要处理这个吗,考虑到我没有使用位图变量?我直接使用drawable的引用形式。附上代码。 - GSree
你不需要考虑小图片的调整大小,但一个活动中有64KB的图片将会给UI带来压力,并消耗内存。将它们转换为位图并将其提供给ImageView。 - Jana
rdhanan.S 什么是64kb?每个活动的图像大小是否有限制?我的图像以png格式为15kb左右。一个活动将有4张图片。因此,大约为15 x 4 = ~60Kb。 - GSree
抱歉,我以为图像只有16KB,无法编辑上面的评论。 - Jana
rdhanan.S 感谢提供链接。我成功编写了一个类似的方法(使用图像资源代替文件),并且运行良好。最后一个问题,你知道“requiredsize”参数的最佳值是多少吗(基于你提供的链接)?我使用了100。看起来还不错。 - GSree

0

你能发布一段包含Activity和stacktrace的代码片段吗?

你已经查看了避免内存泄漏文章吗?

特别是以下部分:

当Drawable附加到视图上时,视图被设置为Drawable的回调。在上面的代码片段中,这意味着Drawable引用了TextView,而TextView本身引用了Activity(Context),后者又引用了几乎任何东西(取决于您的代码)。


我检查了链接。不确定我能否用我的代码做太多事情。已将代码片段更新到问题中。请检查并告诉我是否需要根据此进行一些修改。 - GSree

0

看起来这些图片非常重。我建议启动AsyncTimer,它实际上返回位图实例,并在AsyncTask的doBackground()中传递图像ID并将其重新缩放到所需大小,例如32 x 32,使用Bitmap类的createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)方法。


图片的比例为800 x 600,平均大小为15kb(每个)。您能否发布一些有关如何使用AsyncTimer的代码片段? - GSree

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接