90

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

Thread.setDefaultUncaughtExceptionHandler(
                new DefaultExceptionHandler(this));

在我的实现中,我试图显示一个AlertDialog显示适当的异常消息。

但是,这似乎不起作用。每当任何未处理的线程抛出异常时,我都会得到库存的操作系统默认对话框(“抱歉!-应用程序已停止-意外对话框”)。

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

4

5 回答 5

24

这应该是你需要做的所有事情。(确保您在之后停止该过程 - 事情可能处于不确定状态。)

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

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

于 2010-05-04T21:04:58.920 回答
14

很久以前,我发布了用于自定义处理 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

于 2015-01-24T14:25:07.603 回答
3

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

previousHandler = Thread.getDefaultUncaughtExceptionHandler();
于 2010-05-04T15:11:47.047 回答
2

在你打电话之前它不起作用

android.os.Process.killProcess(android.os.Process.myPid());

在 UncaughtExceptionHandler 的最后。

于 2014-02-26T08:53:17.643 回答
2

FWIW 我知道这有点离题,但我们一直在成功使用Crittercism 的免费计划。他们还提供了一些高级功能,例如处理异常以使应用程序不会崩溃。

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

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


以下是类似的问题:

于 2012-08-28T06:43:46.753 回答