在Android上使用全局异常处理

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

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

alen0pnh

alen0pnh1#

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

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

处理错误的类:

public class BaseActivity extends Activity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread paramThread, Throwable paramThrowable) {
                Log.e("Alert","Lets See if it Works !!!");
            }
        });
    }
}
q9yhzks0

q9yhzks02#

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

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

代码:

public class BaseActivity extends Activity {
    @Override
    public void onCreate() {
        super.onCreate();

        final Thread.UncaughtExceptionHandler oldHandler =
            Thread.getDefaultUncaughtExceptionHandler();

        Thread.setDefaultUncaughtExceptionHandler(
            new Thread.UncaughtExceptionHandler() {
                @Override
                public void uncaughtException(
                    Thread paramThread,
                    Throwable paramThrowable
                ) {
                    //Do your own error handling here

                    if (oldHandler != null)
                        oldHandler.uncaughtException(
                            paramThread,
                            paramThrowable
                        ); //Delegates to Android's error handling
                    else
                        System.exit(2); //Prevents the service/app from freezing
                }
            });
    }
}
jobtbby3

jobtbby33#

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

private Thread.UncaughtExceptionHandler oldHandler;

@Override
public void onCreate() {
    super.onCreate();

    if (!BuildConfig.DEBUG)
        return;

    oldHandler = Thread.getDefaultUncaughtExceptionHandler();
    Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
        try {
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));

            Intent intent = new Intent(Intent.ACTION_SEND);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.putExtra(Intent.EXTRA_TEXT, sw.toString());
            intent.setType("text/plain");
            startActivity(intent);
        } catch(Exception ex) {
            ex.printStackTrace();
        } finally {
            if (oldHandler != null)
                oldHandler.uncaughtException(t, e);
            else
                System.exit(1);
        }
    });
}

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

eagi6jfj

eagi6jfj4#

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

bnl4lu3b

bnl4lu3b5#

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

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

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

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

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

  1. defaultEh的引用即使在Activity完成后也会保留在堆中,因为它由引用链使用,因此可能发生的最坏情况是内存不足异常。
    因此,我又添加了一件事,最终使这个工作没有问题:
private static boolean customExceptionHandlerAttached = false;                                                                                                                                                                                                                                                                                                                                                                      

@Override                                                                                                                                                                                                                                                                                                                                                                                                                           
protected void onCreate(@Nullable Bundle savedInstanceState) {                                                                                                                                                                                                                                                                                                                                                                      
    super.onCreate(savedInstanceState);                                                                                                                                                                                                                                                                                                                                                                                             

    if(!customExceptionHandlerAttached) {                                                                                                                                                                                                                                                                                                                                                                                            
        final Thread.UncaughtExceptionHandler defaultEH = Thread.getDefaultUncaughtExceptionHandler();                                                                                                                                                                                                                                                                                                                              
        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {                                                                                                                                                                                                                                                                                                                                           
            @Override                                                                                                                                                                                                                                                                                                                                                                                                               
            public void uncaughtException(Thread thread, Throwable e) {                                                                                                                                                                                                                                                                                                                                                             
                 handleUncaughtException(thread, e, defaultEH);                                                                                                                                                                                                                                                                                                                                                                      
            }                                                                                                                                                                                                                                                                                                                                                                                                                       
        });                                                                                                                                                                                                                                                                                                                                                                                                                         
        customExceptionHandlerAttached = true;                                                                                                                                                                                                                                                                                                                                                                                      
    }                                                                                                                                                                                                                                                                                                                                                                                                                               
}

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

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

ni65a41a6#

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

xdnvmnnf

xdnvmnnf7#

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

override fun onCreate() {
        super.onCreate()
        Thread.setDefaultUncaughtExceptionHandler { _, e -> handleUncaughtException(e) }
}

 private fun handleUncaughtException(e: Throwable) {
        if (isUIThread()) invokeLogActivity(e)
        else Handler(Looper.getMainLooper()).post { invokeLogActivity(e) }
    }

    private fun isUIThread(): Boolean {
        return Looper.getMainLooper().thread === Thread.currentThread()
    }

    private fun invokeLogActivity(e: Throwable) {
        val intent = Intent(currentActivity(), ErrorActivity::class.java)
        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
        intent.putExtra("stackTrace", getStackTraceAsString(e))
        startActivity(intent)
        exitProcess(1)
    }

    private fun getStackTraceAsString(throwable: Throwable): String {
        val sw = StringWriter()
        val pw = PrintWriter(sw)
        throwable.printStackTrace(pw)
        return sw.toString()
    }

相关问题