【问题标题】:Avoid crashing the Handler thread in case of Runtime Exception?避免在运行时异常的情况下使处理程序线程崩溃?
【发布时间】:2014-03-18 05:49:57
【问题描述】:

我有一个处理程序(线程),我在上面发布了 Runnables。如果一个 Runnable 错误地抛出了 RuntimeException,整个应用程序进程就会崩溃。作为默认设置,这听起来很合理,但我想捕获此类运行时异常,记录错误并继续运行。不过,我很难做到这一点。我想到了以下选项:

  1. 子类Looper 并覆盖loop(),其中包含调用已发布Runnables 的run() 方法的代码。这不起作用,因为 Looper 是最终的。
  2. 子类HandlerThread 并覆盖调用Looper.loop() 的run 方法。如果出现运行时异常,请再次调用super.run(),依此类推。这不起作用,因为“每个线程只能创建一个 Looper”。
  3. 在每个可运行类中,包含一个用于运行时异常的 try-catch。这会起作用,但很烦人,因为我有很多不同的 Runnable 类。此外,如果可运行对象错误地忘记包含 try-catch,则不会保护处理程序线程。

在理想情况下,Looper 将有一个名为 registerExceptionHandler(ExceptionHandler) 的成员方法,然后在出现异常时调用 ExceptionHandler

有人有更好的建议吗?

【问题讨论】:

  • 把runnable的代码放到try-catch块中,捕获异常。所以 runnable 不会抛出捕获的异常。您可以根据需要管理 catch 块中的异常。
  • 对,我认为这就是我所说的选项 3,我认为这是一种解决方法。问题是我有几个 Runnable 类,并且希望避免将这样的代码添加到每个类中。

标签: android android-handler


【解决方案1】:

试试这个自定义处理程序:

class H extends Handler {
    public H(Looper looper) {
        super(looper);
    }

    @Override
    public void dispatchMessage(Message msg) {
        // catch any Exception
        try {
            super.dispatchMessage(msg);
        } catch (Exception e) {
            Log.d(TAG, "dispatchMessage " + e.getMessage());
        }
    }
}

测试代码:

HandlerThread ht = new HandlerThread("hthread");
ht.start();
Handler h = new H(ht.getLooper());

Runnable r = new Runnable() {
    @Override
    public void run() {
        throw new RuntimeException("testing exception");
    }
};
h.post(r);
h.post(r);

【讨论】:

  • 是的,这就是您设置和启动 HandlerThread 的方式。如果您执行ht.post(new RuntimeGeneratingRunnable) 之类的操作,应用程序进程将崩溃。知道如何避免这种情况吗?
  • 不要使用 Runnables,使用 sendMessage 和 Handler.Callback
  • 对,那行得通。我将不得不转换为使用消息而不是 Runnables,所以我想我更愿意将 try-catch 添加到所有 Runnables 中......如果没有更好的办法出现。
  • 或者,您也可以使用 Runnables,但您需要使用覆盖 dispatchMessage 方法的自定义处理程序:try { super.等
  • 请更新您的答案以符合问题创建者的要求。 :)
【解决方案2】:

在一个完美的世界里DefaultExceptionHandler 在整个申请过程中对我来说就像一个魅力。当它导致未处理的异常时,它会触发。

名为 Android-Remote-StackTrace 的库。你只需要在你的Application类中注册这些DefaultHandlerException类的广播即可。

片段:

 public class Portfolio extends Application {
 static Portfolio portfolio;
 public void onCreate() {
    super.onCreate();
    portfolio = this;
    ExceptionHandler.register(portfolio);// registering for unhandled Exceptions
   }
 }

您可以使用这些来执行各种任务,例如将日志堆栈跟踪上传到您的服务器或将应用程序崩溃的邮件作为崩溃报告发送给您未处理的堆栈跟踪。

【讨论】:

  • 不完全符合我的要求,但确实看起来很有用。我的直接想法是“恢复”处理程序线程为时已晚,但我不确定。我会调查并告诉你。感谢您的回复!
  • 我看过了。我不知道存在 DefaultExceptionHandler;当然很有趣,值得一读。对于这种特殊情况,这意味着队列中任何待处理的可运行对象都将丢失,并且必须重新启动处理程序线程等。不幸的是,这不是一个很好的选择:-(。
【解决方案3】:

最简单的方法似乎是从 Runnable 派生:

public abstract class RunnableBase implements Runnable
{
    public final void run()
    {
        try {
            runInternal();
        }
        catch(Exception e) {
            // handle the exception
        }
    }

    // to be implemented by concrete subclasses
    protected abstract void runInternal();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-26
    • 2010-10-06
    相关资源
    最近更新 更多