【问题标题】:Android: Force Crash with Uncaught Exception in ThreadAndroid:线程中未捕获的异常强制崩溃
【发布时间】:2013-07-07 09:58:07
【问题描述】:

我正在开发一个应用程序,并且每隔一段时间,我的一个后台工作线程都会有一个未捕获的异常。这些异常使该线程崩溃,但由于它不在 UI 线程上,因此应用程序继续运行。 如何强制后台线程中的这些未捕获的异常使整个应用程序崩溃?如果相同的上下文崩溃信息(例如堆栈跟踪)可用,那就太好了。

我想这样做,以便当我将应用程序发布给我的测试人员时,它不会变得无响应。相反,当后台线程有未捕获的异常时,应用程序将转到它的崩溃处理程序并向我发送报告(我正在使用 ACRA,但这无关紧要)。这比静默失败的应用要好。

【问题讨论】:

    标签: java android exception


    【解决方案1】:

    迟到的答案,但我问自己同样的问题。

    我们在生产环境中使用 Crashlytics,但如果该应用是为开发而构建的,则会启用一些断言,并且记录错误实际上会抛出它,以便我们的开发人员可以检测到任何不正确的行为。

    但正如您所说,在后台线程中抛出错误不会导致应用程序崩溃。

    为了确保应用程序在构建开发时立即崩溃,我们只需在主循环器上使用一个处理程序来在主线程上抛出异常。

    看起来有点像这样:

    
    public static void assertTrue(boolean condition, String msg) {
        if (condition) {
            return;
        }
    
        final IllegalStateException e = new IllegalStateException(message);
        if (BuildConfig.RELEASE) {
            Crashlytics.logException(e);
            return;
        }
    
        Log.e("ASSERT", message, e);
        if (Looper.getMainLooper() != Looper.myLooper()) {
            mMainThreadHandler.post(new Runnable() {
                @Override
                public void run() {
                    throw e;
                }
            });
        }
    
        throw e;
    }
    

    【讨论】:

    • 虽然这看起来是一个很有前途的解决方案,但我还不清楚一些事情:1. 如何避免 run() 中出现“未捕获异常”的 Intellij 错误 2. 你在哪里获得 mainThreadHandler静态上下文?
    【解决方案2】:

    以下为原版

    实际上,经过进一步测试,我发现您可以通过直接将异常交给主线程来简化代码。

    public static <T extends Exception> void throwOnMainThread(T exception) {
        Thread mainThread = Looper.getMainLooper().getThread();
        mainThread.getUncaughtExceptionHandler().uncaughtException(mainThread, exception);
    }
    

    这将使主线程从任何地方崩溃,即使没有设置自定义 UncaughtExceptionHandler 也可以安全调用。

    原答案:

    考虑以下从后台线程中使主线程崩溃的静态方法:

    public static <T extends Exception> void throwOnMainThread(final T exception) {
        Handler mainThreadHandler = new Handler(Looper.getMainLooper());
        mainThreadHandler.post(new Runnable() {
            @Override
            public void run() {
                Thread currentThread = Thread.currentThread();
                currentThread.getUncaughtExceptionHandler().uncaughtException(currentThread, exception);
            }
        });
    }
    

    首先我们通过主 Looper 获得主线程的处理程序。然后我们发布一个 Runnable,它将调用该线程的 UncaughtExceptionHandler 并将其交给我们的异常。

    把它放到一个 utils 类中,你基本上可以从任何地方在主线程上抛出异常。

    然后可以通过使用来实现主线程崩溃

    ThreadUtils.throwOnMainThread(new RuntimeException());
    

    例如。

    【讨论】:

    • 新答案不会导致应用程序崩溃,但 post-method 确实有效
    【解决方案3】:

    您可以在实现java.lang.Thread.UncaughtExceptionHandler 的类中捕获未捕获的异常。

    • 创建一个实现UncaughtExceptionHandler 的类,并将您想要的行为放在uncaughtException 覆盖函数中。
      您可以在此函数中执行任何您想要的行为,例如将日志发送到服务器、向用户显示自定义崩溃对话框等。
    • 在您的活动/线程中添加Thread.setDefaultUncaughtExceptionHandler();并提供您的异常处理程序类的实例。


    【讨论】:

    • 这不适用于所有 Executor 实现。其中一些不调用处理程序。您必须覆盖 afterExecute 并从那里重新抛出 RuntimeException 或 Error 以强制它崩溃。
    猜你喜欢
    • 2010-10-06
    • 2014-06-24
    • 2016-02-09
    • 1970-01-01
    • 2019-07-13
    • 2013-04-11
    • 2016-06-13
    • 2015-09-17
    • 1970-01-01
    相关资源
    最近更新 更多