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

Posted

技术标签:

【中文标题】在 Android 中设置全局未捕获异常处理程序的理想方法【英文标题】:Ideal way to set global uncaught exception Handler in Android 【发布时间】:2011-02-15 09:40:17 【问题描述】:

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

Thread.setDefaultUncaughtExceptionHandler(
                new DefaultExceptionHandler(this));

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

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

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

【问题讨论】:

能否请您分享相同的代码... 如果您想记录您的异常情况,请查看acra.ch。 ACRA 允许您将错误报告发送到 Google-Doc 或通过电子邮件发送给您。 @Alexander 或者您可以只使用适用于 Android 的 Google Analytics,并记录您想要的所有异常... 这可能对***.com/questions/19897628/…有帮助 【参考方案1】:

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

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

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

【讨论】:

“处理错误后抛出未捕获的异常导致崩溃”仍然很重要。我刚刚经历过。在我处理了异常并且没有抛出未捕获的异常后,我的应用程序被锁定了。 @OneWorld Jepp 在这里也一样 - 至少对于锁定部分 - 毕竟似乎没有办法“拯救”应用程序崩溃。 @Zainodis 我对这个问题发布了一个稍微偏离主题的答案,并提供了 Crittercism 的链接——我认为他们有一个功能可以让你“保存”应用程序以免崩溃。不确定 - 我只使用免费版 atm。 @RichardLeMesurier 感谢您的提示 - 我会检查一下 :) ! 奇怪!!!即使我在活动中处理异常,也会调用 uncaughtexception。任何想法。【参考方案2】:

很久以前,我发布了简单的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

【讨论】:

正如人们可能猜到的那样,这种方式不仅可以显示自定义错误对话框,还可以让用户忽略异常并继续使用应用程序(虽然这看起来是个坏主意对于已发布的应用程序,在调试或测试会话期间可能非常方便)。 嗨,虽然这可以捕获未捕获的异常,但由于某种原因,此代码总是抛出异常。最初我虽然是因为您在 startCatcher 方法中拥有的 RuntimeException 行,但在删除它后我仍然遇到异常。我不确定这是否是必需的。无论如何,我得到的例外是java.lang.RuntimeException: Performing pause of activity that is not resumed。我相信当我尝试启动自己的 Looper 时,系统会暂停即将开始的活动?我不确定,但任何帮助将不胜感激。谢谢 另外,如果我删除 startCatcher,即在没有您的代码的情况下运行应用程序,那么一切正常,没有任何异常。 @sttaq 你用的是什么版本的安卓? 我想我是在 2.3.x 上尝试的【参考方案3】:

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

previousHandler = Thread.getDefaultUncaughtExceptionHandler();

【讨论】:

【参考方案4】:

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

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

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


以下是类似的问题:

Global uncaught exception handler -> email log to me? Is it possible to create some sort of global exception handler in Android?

【讨论】:

【参考方案5】:

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

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

在 UncaughtExceptionHandler 的最后。

【讨论】:

以上是关于在 Android 中设置全局未捕获异常处理程序的理想方法的主要内容,如果未能解决你的问题,请参考以下文章

Android视图:未捕获的处理程序:线程主因未捕获的异常而退出

Android应用捕获全局异常自定义处理

Kotlin 协程协程异常处理 ④ ( Android 协程中出现异常导致应用崩溃 | Android 协程中使用协程异常处理器捕获异常 | Android 全局异常处理器 )

Kotlin 协程协程异常处理 ④ ( Android 协程中出现异常导致应用崩溃 | Android 协程中使用协程异常处理器捕获异常 | Android 全局异常处理器 )

Android_程序未处理异常的捕获与处理

Winform 全局异常捕获