在Android中设置全局未捕获异常处理程序的理想方法

时间:2010-05-04 10:12:52

标签: android exception-handling uncaught-exception

我想为Android应用程序中的所有线程设置一个全局未捕获的异常处理程序。因此,在我的Application子类中,我将Thread.UncaughtExceptionHandler的实现设置为未捕获异常的默认处理程序。

Thread.setDefaultUncaughtExceptionHandler(
                new DefaultExceptionHandler(this));

在我的实现中,我试图显示AlertDialog显示相应的异常消息。

但是,这似乎不起作用。无论何时,对于任何未处理的线程抛出异常,我都会获得库存操作系统默认对话框(“抱歉!-Application-have-stopped-unexpectedly dialog”)。

为未捕获的异常设置默认处理程序的正确和理想方法是什么?

5 个答案:

答案 0 :(得分:23)

这应该就是你需要做的一切。 (确保你事后停止过程 - 事情可能处于不确定的状态。)

要检查的第一件事是Android处理程序是否仍然被调用。您的版本可能被调用但是致命失败,并且system_server在看到进程崩溃时显示通用对话框。

在处理程序的顶部添加一些日志消息,看它是否到达那里。从getDefaultUncaughtExceptionHandler打印结果,然后抛出未捕获的异常以导致崩溃。密切注意logcat输出,看看发生了什么。

答案 1 :(得分:10)

我很久以前发布了简单的solution用于Android崩溃的自定义处理。它有点hacky但它​​适用于所有Android版本(包括Lollipop)。

首先是一点理论。在Android中使用未捕获的异常处理程序时的主要问题是在主(也称为UI)线程中引发的异常。这就是原因。当应用启动系统调用ActivityThread.main方法时,该方法会准备并启动应用的Main looper

public static void main(String[] args) {
  …
  …
    Looper.prepareMainLooper();
  …
    Looper.loop();
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

Main looper负责处理UI线程中发布的消息(包括与UI呈现和交互相关的所有消息)。如果在UI线程中抛出异常,它将被您的异常处理程序捕获,但由于您没有使用loop()方法,因此您无法向用户显示任何对话或活动因为没有人为你处理UI消息。

建议的解决方案非常简单。我们自己运行Looper.loop方法并用try-catch块包围它。捕获异常时,我们会根据需要进行处理(例如,启动我们的自定义报告活动)并再次调用Looper.loop方法。

以下方法演示了此技术(应该从Application.onCreate侦听器调用):

private void startCatcher() {
    UncaughtExceptionHandler systemUncaughtHandler = Thread.getDefaultUncaughtExceptionHandler();

    // the following handler is used to catch exceptions thrown in background threads
    Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler(new Handler()));

    while (true) {
        try {
            Looper.loop();
            Thread.setDefaultUncaughtExceptionHandler(systemUncaughtHandler);
            throw new RuntimeException("Main thread loop unexpectedly exited");
        } catch (Throwable e) {
            showCrashDisplayActivity(e);
        }
    }
}

正如您所看到的,未捕获的异常处理程序仅用于后台线程中抛出的异常。以下处理程序捕获这些异常并将它们传播到UI线程:

static class UncaughtHandler implements UncaughtExceptionHandler {

    private final Handler mHandler;

    UncaughtHandler(Handler handler) {
        mHandler = handler;
    }

    public void uncaughtException(Thread thread, final Throwable e) {
        mHandler.post(new Runnable() {
            public void run() {
                throw new BackgroundException(e);
            }
        });
    }
}

我的GitHub仓库中提供了使用此技术的示例项目:https://github.com/idolon-github/android-crash-catcher

答案 2 :(得分:3)

我认为在你的uncaughtException()方法中禁用它不要调用previousHandler.uncaughtException(),其中previousHandler由

设置
previousHandler = Thread.getDefaultUncaughtExceptionHandler();

答案 3 :(得分:3)

FWIW我知道这有点偏离主题,但我们一直在使用Crittercism's free plan成功。它们还提供一些高级功能,例如处理异常,以便应用程序不会崩溃。

在免费版本中,用户仍然看到崩溃,但至少我收到了电子邮件和堆栈跟踪。

我们也使用iOS版本(但我从同事那里听说它不太好。)


以下是类似的问题:

答案 4 :(得分:1)

在你致电

之前它不起作用
android.os.Process.killProcess(android.os.Process.myPid());

在UncaughtExceptionHandler的最后。