【问题标题】:Catching OutOfMemoryError in decoding Bitmap在解码位图时捕获 OutOfMemoryError
【发布时间】:2011-10-31 14:31:37
【问题描述】:

即使您尝试了一些减少内存使用的方法,捕捉 OutOfMemoryError 是否也是一种好习惯?还是我们不应该捕获异常?哪一个更好?

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

谢谢

【问题讨论】:

标签: android bitmap out-of-memory


【解决方案1】:

最好抓住一次,再给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.
    }
}

【讨论】:

  • 调用 System.gc() 可能不是个好主意,http://code.google.com/p/android/issues/detail?id=8488#c80,无论如何,谢谢
  • 这里你不用担心,因为你还没有加载位图。所以调用GC是安全的。完成后请务必致电bitmap.recycle()
  • “优雅地处理”应该怎么做?我不确定如何以友好的方式向用户解释这一点。告诉他们转到其他应用程序并单击返回?要求他们重新启动?
  • 您可能应该第二次尝试使用更高的inSampleSize 值。如果即使在那之后它仍然不起作用,那么您可以显示一条消息,告诉用户图像加载操作失败,应该再次尝试相同的操作。..
  • 如果您不能/不想使用更高的 inSampleSize,也可以尝试在清单中添加 android:largeHeap="true"。
【解决方案2】:

我做了这样的事情:我发现错误只是为了尝试缩小图像直到它起作用。最终它根本无法工作;然后返回空值;否则,成功返回位图。

我决定如何处理位图是否为空。

// 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 次,然后就可以工作了。

【讨论】:

  • 这似乎是一个不错的解决方案,我想尝试一下,但无法弄清楚第 7 行的 w 和 h 变量是什么?
  • @GaryHost:w 和 h 是我们将放置位图的 ImageView 的宽度和高度。答案已更新。
  • 谢谢各位,我采纳了你的解决方案 :)
【解决方案3】:

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

  1. 使用 try-catch 捕获 OutOfMemoryError
  2. 由于出现此错误,您的活动可能会变得不稳定,请重新启动它。
  3. 您可以禁用动画,以使用户不知道该活动已重新启动。
  4. 您可以添加一些额外的数据,以了解应用在上次运行期间崩溃了。

我的做法是:

    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;
    }

然后在 Activity 的 onCreate 上你可以恢复(类似这样):

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

这种方法保存了我的应用程序。 希望对你也有帮助!!

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

    • 关于选项的好消息。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 2011-04-18
    • 1970-01-01
    • 2023-03-20
    • 2014-08-13
    • 1970-01-01
    相关资源
    最近更新 更多