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


88

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

Thread.setDefaultUncaughtExceptionHandler(
                new DefaultExceptionHandler(this));

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

但是,这似乎不起作用。无论何时,任何未处理的线程都会引发异常,我得到了库存的OS默认对话框(“抱歉!-应用程序已停止-意外对话框”)。

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


1
您能为同一人共享代码吗?
Code_Life 2012年

2
如果你想记录你的例外,看看acra.ch。ACRA允许您将错误报告发送给Google文档或通过电子邮件发送给您。
2013年

1
@Alexander或者您可以仅使用Android的Google Analytics(分析),并记录所需的所有异常...
IgorGanapolsky 2013年

Answers:


24

那应该就是您要做的。(确保您之后使进程停止运行-事情可能处于不确定状态。)

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

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


10
“处理错误后引发未捕获的异常导致崩溃”仍然很重要。我刚刚经历了。处理异常后,我的应用程序被锁定,并且未引发未捕获的异常。
OneWorld

@OneWorld Jepp同样在这里-至少对于锁定部分而言-似乎根本没有办法“保存”应用程序免于崩溃。
AgentKnopf

@Zainodis我对这个问题发布了一个稍微偏离主题的答案,提供了与Crittercism的链接-我认为它们具有一项功能,使您可以“保存”应用程序的崩溃信息。不确定-我仅使用免费版本的atm。
理查德·勒·梅苏里尔

@RichardLeMesurier感谢您的提示-我将检查一下:)!
AgentKnopf 2012年

奇怪!!!即使我主动地处理异常,也会调用uncaughtexception。任何的想法。
Hiren Dabhi 2013年

12

我很久以前发布了用于自定义处理Android崩溃的简单解决方案。这有点小巧,但是它可以在所有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");
}

主循环程序负责处理在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


就像人们可能猜到的那样,这样不仅可以显示自定义错误对话框,而且还可以使用户忽略异常并继续使用该应用程序(尽管对于已发布的应用程序来说似乎是个坏主意,在调试或测试期间非常方便)。
Idolon 2015年

嗨,虽然这可以捕获未捕获的异常,但是由于某种原因,此代码始终会抛出异常。最初,我虽然是因为startCatcher方法中包含RuntimeException行,但是删除它后仍然出现异常。我不确定这是否是必需的。无论如何,我得到的例外是java.lang.RuntimeException: Performing pause of activity that is not resumed。我相信当我尝试启动自己的循环程序时,系统会暂停即将开始的活动吗?我不确定,但会有所帮助。谢谢
sttaq 2015年

另外,如果我删除了startCatcher,即在不使用您的代码的情况下运行应用程序,那么一切正常,没有任何异常。
sttaq

@sttaq您使用什么版本的Android?
Idolon

我想我在2.3.x上尝试过
sttaq 2015年

3

我想禁用uncaughtException()方法中的方法,不要调用previousHandler.uncaughtException(),其中previousHandler设置为

previousHandler = Thread.getDefaultUncaughtExceptionHandler();

2

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

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

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


这是类似的问题:


1

直到您打电话才起作用

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

在您的UncaughtExceptionHandler的末尾。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.