在Android上使用全局异常处理

wnvonmuf  于 2023-06-20  发布在  Android
关注(0)|答案(7)|浏览(146)

是否有代码示例或教程介绍如何使用Thread.setDefaultUncaughtExceptionHandler方法?基本上,我试图在应用程序中显示一个自定义的警报对话框,每当抛出一个异常时。有可能做到这一点吗?我知道如果在UI线程中抛出异常,在屏幕上显示一些东西是有点棘手的,但我不知道有什么方法可以解决这个问题。

alen0pnh

alen0pnh1#

基本的例子,有人谁来到这个页面的解决方案:)

  1. public class ChildActivity extends BaseActivity {
  2. @SuppressWarnings("unused")
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. int a=1/0;
  7. }
  8. }

处理错误的类:

  1. public class BaseActivity extends Activity{
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
  6. @Override
  7. public void uncaughtException(Thread paramThread, Throwable paramThrowable) {
  8. Log.e("Alert","Lets See if it Works !!!");
  9. }
  10. });
  11. }
  12. }
展开查看全部
q9yhzks0

q9yhzks02#

下面是the answerMohit Sharma变体,具有以下改进:

  • 错误处理后不会导致应用程序/服务冻结
  • 让Android在您自己的错误处理之后进行正常的错误处理

代码:

  1. public class BaseActivity extends Activity {
  2. @Override
  3. public void onCreate() {
  4. super.onCreate();
  5. final Thread.UncaughtExceptionHandler oldHandler =
  6. Thread.getDefaultUncaughtExceptionHandler();
  7. Thread.setDefaultUncaughtExceptionHandler(
  8. new Thread.UncaughtExceptionHandler() {
  9. @Override
  10. public void uncaughtException(
  11. Thread paramThread,
  12. Throwable paramThrowable
  13. ) {
  14. //Do your own error handling here
  15. if (oldHandler != null)
  16. oldHandler.uncaughtException(
  17. paramThread,
  18. paramThrowable
  19. ); //Delegates to Android's error handling
  20. else
  21. System.exit(2); //Prevents the service/app from freezing
  22. }
  23. });
  24. }
  25. }
展开查看全部
jobtbby3

jobtbby33#

对于那些只想在设备上(在调试配置中)看到应用崩溃时的异常详细信息的人。这是应用程序类:

  1. private Thread.UncaughtExceptionHandler oldHandler;
  2. @Override
  3. public void onCreate() {
  4. super.onCreate();
  5. if (!BuildConfig.DEBUG)
  6. return;
  7. oldHandler = Thread.getDefaultUncaughtExceptionHandler();
  8. Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
  9. try {
  10. StringWriter sw = new StringWriter();
  11. e.printStackTrace(new PrintWriter(sw));
  12. Intent intent = new Intent(Intent.ACTION_SEND);
  13. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  14. intent.putExtra(Intent.EXTRA_TEXT, sw.toString());
  15. intent.setType("text/plain");
  16. startActivity(intent);
  17. } catch(Exception ex) {
  18. ex.printStackTrace();
  19. } finally {
  20. if (oldHandler != null)
  21. oldHandler.uncaughtException(t, e);
  22. else
  23. System.exit(1);
  24. }
  25. });
  26. }

它使用外部应用程序,因为您的UI线程可能不再工作。

展开查看全部
eagi6jfj

eagi6jfj4#

请记住,The RuntimePermission("setDefaultUncaughtExceptionHandler")是在设置处理程序之前检查的,并确保在设置处理程序之后通过抛出未捕获的异常来使进程停止,因为事情可能处于不确定状态。
不要显示任何东西,实际上UI线程可能已经崩溃了,写一个日志和/或发送详细信息到服务器,而不是。你可能想看看this question and its answers

bnl4lu3b

bnl4lu3b5#

我只是想指出我到目前为止的经验。我正在使用https://stackoverflow.com/a/26560727/2737240建议的解决方案,在将控制权交给默认异常处理程序之前,将异常刷新到日志文件中。
然而,我的结构看起来像这样:

  1. BaseActivity
  2. |
  3. _______________________
  4. | | |
  5. Activity A Activity B Activity C
  1. final Thread.UncaughtExceptionHandler defaultEH = Thread.getDefaultUncaughtExceptionHandler();
  2. Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
  3. @Override
  4. public void uncaughtException(Thread thread, Throwable e) {
  5. handleUncaughtException(thread, e, defaultEH);
  6. }
  7. });

其中handleUncaughtException(thread, e, defaultEH);写入日志并将调用移交给原始UncaughtExceptionHandler。
所以使用这段代码会发生以下情况:

  • 活动A已示例化
  • 新的默认异常处理程序(DEH)现在是我的日志处理程序+旧的DEH
  • 活动B已示例化
  • 新DEH现在是我的日志处理器+旧DEH(日志处理器+原DEH)
  • 活动C已示例化
  • 新DEH现在是我的日志处理器+旧DEH(日志处理器+日志处理器+原DEH)

所以这是一个无限增长的链条,导致了两个问题:
1.指定的自定义代码(在我的例子中是写入日志文件)将被多次调用,这不是所需的操作。

  1. defaultEh的引用即使在Activity完成后也会保留在堆中,因为它由引用链使用,因此可能发生的最坏情况是内存不足异常。
    因此,我又添加了一件事,最终使这个工作没有问题:
  1. private static boolean customExceptionHandlerAttached = false;
  2. @Override
  3. protected void onCreate(@Nullable Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. if(!customExceptionHandlerAttached) {
  6. final Thread.UncaughtExceptionHandler defaultEH = Thread.getDefaultUncaughtExceptionHandler();
  7. Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
  8. @Override
  9. public void uncaughtException(Thread thread, Throwable e) {
  10. handleUncaughtException(thread, e, defaultEH);
  11. }
  12. });
  13. customExceptionHandlerAttached = true;
  14. }
  15. }

通过此解决方案,我们可以确保:

  • 为所需的操作添加自定义异常处理程序
  • 确保此操作仅触发一次
  • 允许垃圾收集器通过调用finish()完全处理我们的活动
展开查看全部
ni65a41a

ni65a41a6#

如果要使用此库
https://github.com/selimtoksal/Android-Caught-Global-Exception-Library
创建你的TransferObject不是所有的在你的活动中只是在基本活动中使用

xdnvmnnf

xdnvmnnf7#

您需要在应用程序类中添加以下代码

  1. override fun onCreate() {
  2. super.onCreate()
  3. Thread.setDefaultUncaughtExceptionHandler { _, e -> handleUncaughtException(e) }
  4. }
  5. private fun handleUncaughtException(e: Throwable) {
  6. if (isUIThread()) invokeLogActivity(e)
  7. else Handler(Looper.getMainLooper()).post { invokeLogActivity(e) }
  8. }
  9. private fun isUIThread(): Boolean {
  10. return Looper.getMainLooper().thread === Thread.currentThread()
  11. }
  12. private fun invokeLogActivity(e: Throwable) {
  13. val intent = Intent(currentActivity(), ErrorActivity::class.java)
  14. intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
  15. intent.putExtra("stackTrace", getStackTraceAsString(e))
  16. startActivity(intent)
  17. exitProcess(1)
  18. }
  19. private fun getStackTraceAsString(throwable: Throwable): String {
  20. val sw = StringWriter()
  21. val pw = PrintWriter(sw)
  22. throwable.printStackTrace(pw)
  23. return sw.toString()
  24. }
展开查看全部

相关问题