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

发布于 2024-08-31 13:41:30 字数 437 浏览 2 评论 0原文

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

Thread.setDefaultUncaughtExceptionHandler(
                new DefaultExceptionHandler(this));

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

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

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

I want to set a global uncaught exception handler for all the threads in my Android application. So, in my Application subclass I set an implementation of Thread.UncaughtExceptionHandler as default handler for uncaught exceptions.

Thread.setDefaultUncaughtExceptionHandler(
                new DefaultExceptionHandler(this));

In my implementation, I am trying to display an AlertDialog displaying appropriate exception message.

However, this doesn't seem to work. Whenever, an exception is thrown for any thread which goes un-handled, I get the stock, OS-default dialog ("Sorry!-Application-has-stopped-unexpectedly dialog").

What is the correct and ideal way to set a default handler for uncaught exceptions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

路还长,别太狂 2024-09-07 13:41:30

这应该就是您需要做的全部。 (确保随后让进程停止——事情可能处于不确定状态。)

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

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

That should be all you need to do. (Make sure you cause the process to halt afterward -- things could be in an uncertain state.)

The first thing to check is whether the Android handler is still getting called. It's possible that your version is being called but failing fatally and the system_server is showing a generic dialog when it sees the process crash.

Add some log messages at the top of your handler to see if it's getting there. Print the result from getDefaultUncaughtExceptionHandler and then throw an uncaught exception to cause a crash. Keep an eye on the logcat output to see what's going on.

自找没趣 2024-09-07 13:41:30

我很久以前发布了用于自定义处理 Android 崩溃的简单解决方案。虽然有点老套,但它适用于所有 Android 版本(包括 Lollipop)。

首先介绍一点理论。在 Android 中使用未捕获的异常处理程序时,主要问题是在主(又名 UI)线程中抛出异常。这就是原因。当应用程序启动系统调用 ActivityThread.main 方法,用于准备并启动 Main Looper of your app:

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 存储库上提供了使用此技术的示例项目:

I posted the simple solution for custom handling of Android crashes a long ago. It's a little hacky however it works on all Android versions (including the Lollipop).

First a little bit of theory. The main issues when you use uncaught exception handler in Android come with the exceptions thrown in the main (aka UI) thread. And here is why. When the app starts system calls ActivityThread.main method which prepares and starts the Main looper of your app:

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

Main looper is responsible for processing messages posted in the UI thread (including all messages related to UI rendering and interaction). If an exception is thrown in the UI thread it will be caught by your exception handler, but since you're out of loop() method you won't be able to show any dialog or activity to the user as there's no one left to process UI messages for you.

The proposed solution is quite simple. We run Looper.loop method by our own and surround it with try-catch block. When an exception is caught we process it as we want (for example start our custom report activity) and call Looper.loop method again.

The following method demonstrates this technique (it should be called from the Application.onCreate listener):

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

As you can see the uncaught exception handler is used only for the exceptions thrown in background threads. The following handler catches those exceptions and propagates them to the UI thread:

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

An example project which uses this technique is available on my GitHub repo: https://github.com/idolon-github/android-crash-catcher

无人问我粥可暖 2024-09-07 13:41:30

我认为要在 uncaughtException() 方法中禁用它,请不要调用 previousHandler.uncaughtException() ,其中 previousHandler 设置为

previousHandler = Thread.getDefaultUncaughtExceptionHandler();

I think to disable that in your uncaughtException() method do not call previousHandler.uncaughtException() where previousHandler is set by

previousHandler = Thread.getDefaultUncaughtExceptionHandler();
寂寞清仓 2024-09-07 13:41:30

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

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

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


以下是类似的问题:

FWIW I know this is slightly off-topic, but we've been using Crittercism's free plan with success. They also offer some premium features, like handling the exception so the app doesn't crash.

In the free version, the user still sees the crash, but at least I get the email and the stack trace.

We also use the iOS version (but I've heard from my colleagues that it is not quite as good).


Here are similar questions:

满天都是小星星 2024-09-07 13:41:30

调用它才起作用。

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

直到您在 UncaughtExceptionHandler 的最后

It doesn't work until you call

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

at the very end of your UncaughtExceptionHandler.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文