在 Android 中设置全局未捕获异常处理程序的理想方式
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2764394/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Ideal way to set global uncaught exception Handler in Android
提问by Samuh
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.
我想为我的 Android 应用程序中的所有线程设置一个全局未捕获的异常处理程序。因此,在我的Application
子类中,我Thread.UncaughtExceptionHandler
为未捕获的异常设置了作为默认处理程序的实现。
Thread.setDefaultUncaughtExceptionHandler(
new DefaultExceptionHandler(this));
In my implementation, I am trying to display an AlertDialog
displaying appropriate exception message.
在我的实现中,我试图显示一个AlertDialog
显示适当的异常消息。
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?
为未捕获的异常设置默认处理程序的正确和理想的方法是什么?
采纳答案by fadden
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.
首先要检查的是 Android 处理程序是否仍在被调用。您的版本可能正在被调用但失败了,并且当 system_server 看到进程崩溃时,它会显示一个通用对话框。
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.
在处理程序的顶部添加一些日志消息以查看它是否到达那里。从 getDefaultUncaughtExceptionHandler 打印结果,然后抛出一个未捕获的异常导致崩溃。密切关注 logcat 输出以了解发生了什么。
回答by Idolon
I posted the simple solutionfor custom handling of Android crashes a long ago. It's a little hacky however it works on all Android versions (including the Lollipop).
很久以前,我发布了自定义处理 Android 崩溃的简单解决方案。它有点笨拙,但它适用于所有 Android 版本(包括 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.mainmethod which prepares and starts the Main looperof your app:
首先是一点点理论。在 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 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.
主循环器负责处理发布在 UI 线程中的消息(包括所有与 UI 渲染和交互相关的消息)。如果在 UI 线程中抛出异常,它会被您的异常处理程序捕获,但由于您已退出loop()
方法,您将无法向用户显示任何对话框或活动,因为没有人可以处理 UI 消息为你。
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.
建议的解决方案非常简单。我们Looper.loop
自己运行方法并用 try-catch 块包围它。当异常被捕获时,我们会根据需要处理它(例如启动我们的自定义报告活动)并Looper.loop
再次调用方法。
The following method demonstrates this technique (it should be called from the Application.onCreate
listener):
以下方法演示了此技术(应从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);
}
}
}
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:
如您所见,未捕获的异常处理程序仅用于后台线程中抛出的异常。以下处理程序捕获这些异常并将它们传播到 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);
}
});
}
}
An example project which uses this technique is available on my GitHub repo: https://github.com/idolon-github/android-crash-catcher
我的 GitHub 存储库中提供了使用此技术的示例项目:https: //github.com/idolon-github/android-crash-catcher
回答by Richard Le Mesurier
FWIW I know this is slightly off-topic, but we've been using Crittercism's free planwith success. They also offer some premium features, like handling the exception so the app doesn't crash.
FWIW 我知道这有点偏离主题,但我们一直在成功地使用Crittercism 的免费计划。它们还提供了一些高级功能,例如处理异常以便应用程序不会崩溃。
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).
我们也使用 iOS 版本(但我从我的同事那里听说它不太好)。
Here are similar questions:
下面是类似的问题:
回答by Robby Pond
I think to disable that in your uncaughtException() method do not call previousHandler.uncaughtException() where previousHandler is set by
我想在你的 uncaughtException() 方法中禁用它,不要调用 previousHandler.uncaughtException() ,其中 previousHandler 是由
previousHandler = Thread.getDefaultUncaughtExceptionHandler();
回答by Joseph_Marzbani
It doesn't work until you call
在你打电话之前它不起作用
android.os.Process.killProcess(android.os.Process.myPid());
at the very end of your UncaughtExceptionHandler.
在 UncaughtExceptionHandler 的最后。