在解码位图时捕获OutOfMemoryError

时间:2011-08-21 13:52:49

标签: android bitmap out-of-memory

即使您已尝试过一些减少内存使用量的方法,捕获OutOfMemoryError是一个好习惯吗?或者我们应该不抓住异常?哪一个更好的做法?

try {
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inSampleSize = 4;
    bitmap = BitmapFactory.decodeFile(file, options);
} catch (OutOfMemoryError e) {
    e.printStackTrace();
}

由于

4 个答案:

答案 0 :(得分:36)

抓住一次并给予decodeFile另一次机会是一种好习惯。抓住它并呼叫System.gc()并再次尝试解码。调用System.gc()后,它很可能会起作用。

try {
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inSampleSize = 4;
    bitmap = BitmapFactory.decodeFile(file, options);
 } catch (OutOfMemoryError e) {
    e.printStackTrace();

    System.gc();

    try {
        bitmap = BitmapFactory.decodeFile(file);
    } catch (OutOfMemoryError e2) {
      e2.printStackTrace();
      // handle gracefully.
    }
}

答案 1 :(得分:9)

我做了类似这样的事情:我只是为了尝试缩小图像直到它工作才捕获错误。最终它根本无法运作;然后返回null;否则,成功返回位图。

外面我决定如何处理位图,无论它是否为空。

// Let w and h the width and height of the ImageView where we will place the Bitmap. Then:

// Get the dimensions of the original bitmap
BitmapFactory.Options bmOptions= new BitmapFactory.Options();
bmOptions.inJustDecodeBounds= true;
BitmapFactory.decodeFile(path, bmOptions);
int photoW= bmOptions.outWidth;
int photoH= bmOptions.outHeight;

// Determine how much to scale down the image. 
int scaleFactor= (int) Math.max(1.0, Math.min((double) photoW / (double)w, (double)photoH / (double)h));    //1, 2, 3, 4, 5, 6, ...
scaleFactor= (int) Math.pow(2.0, Math.floor(Math.log((double) scaleFactor) / Math.log(2.0)));               //1, 2, 4, 8, ...

// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds= false;
bmOptions.inSampleSize= scaleFactor;
bmOptions.inPurgeable= true;

do
{
    try
    {
        Log.d("tag", "scaleFactor: " + scaleFactor);
        scaleFactor*= 2;
        bitmap= BitmapFactory.decodeFile(path, bmOptions);
    }
    catch(OutOfMemoryError e)
    {
        bmOptions.inSampleSize= scaleFactor;
        Log.d("tag", "OutOfMemoryError: " + e.toString());
    }
}
while(bitmap == null && scaleFactor <= 256);

if(bitmap == null)
    return null;

例如,对于3264x2448的图像,循环在我的手机上迭代2次,然后就可以了。

答案 2 :(得分:0)

如果要显示较小的图像/不同的图像/向用户显示自定义错误消息,则需要捕获它。 您的图像访问包装器可以捕获这些错误并返回代码中定义的一些自定义错误代码;您使用此代码的活动可以决定如何处理错误代码 - 警告用户,强制他退出时使用比android系统提供的更好的错误消息等。

顺便说一句,您没有在示例代码中使用options变量。

答案 3 :(得分:0)

虽然使用try-catch捕获OutOfMemoryError可能不是一个好主意。但是,有时你别无选择,因为我们所有人都讨厌app崩溃。 所以,你可以做的是

  1. 使用try-catch
  2. 捕获OutOfMemoryError
  3. 因为,在此错误之后您的活动可能会变得不稳定,请重新启动它。
  4. 您可以禁用动画,以便用户不知道该活动已重新启动。
  5. 您可以在意图中添加一些额外的数据,以便知道应用程序在之前的运行中崩溃了。
  6. 我是怎么做的:

        try {
            //code that causes OutOfMemoryError
        } catch (Exception e) {
            // in case of exception handle it
            e.printStackTrace();
        } catch (OutOfMemoryError oome)
        {
            //restart this activity
            Intent i=this.getIntent();
            i.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); //disable animation
    
            //EXTRA_ABNORMAL_SHUTDOWN is user defined       
            i.putExtra(this.EXTRA_ABNORMAL_SHUTDOWN, true);
            //put extra data into intent if you like
    
            finish(); //and finish the activity
            overridePendingTransition(0, 0);
            startActivity(i); //then start it(there is also restart method in newer API)
            return false;
        }
    

    然后在onCreate of Activity上你可以恢复(像这样):

    boolean abnormalShutdown=getIntent().getBooleanExtra(this.EXTRA_ABNORMAL_SHUTDOWN, false);
    if (abnormalShutdown)
    {
        //Alert user for any error
        //get any extra data you put befor restarting.
    }
    

    此方法保存了我的应用。 希望它也能帮到你!!