Eclipse - 在 Android 应用程序上引发未处理的异常时中断用户代码
Posted
技术标签:
【中文标题】Eclipse - 在 Android 应用程序上引发未处理的异常时中断用户代码【英文标题】:Eclipse - break on user code when unhandled exception is raised on Android App 【发布时间】:2016-10-19 19:23:14 【问题描述】:我的问题很简单:
我使用 Ecplise(Luna 或 Neon)在 android 上进行开发,我不想使用 Android Studio
我希望仅在导致异常的堆栈的最后一个用户代码调用上调试 ALL 未处理异常的中断(因此,例如,我不想中断一个无用的 ZygonteInit&MethodAndArgsCaller.run(),当由于将空引用传递给原生 Android SDK 方法而导致异常时)。
我知道我可以在断点视图中为特定异常设置断点 (NullPointerException..Throwable...),但我想在所有未处理的情况下中断。 我知道我可以通过在 Java 调试选项中设置“步骤过滤器”来过滤调试,但在我的情况下,这不适用于所有异常。
编辑
在我的堆栈下方的图像中,当引发异常时(在我的代码中除以零)
如果我在引发异常后设置了默认的未捕获异常处理程序,则主线程的堆栈。
【问题讨论】:
我会尝试执行以下操作:1. 实现自己的自定义 UncoughtExceptionHandler(请参阅Using Global Exception Handling on android)和 2. 在该处理程序上使用条件断点 - 对于条件检查堆栈跟踪是否包含你的一个类。 @Robert 感谢您提出的解决方案。我确实尝试过这个解决方案,但问题是 UncoughtExceptionHandler 由另一个线程处理,而导致异常的线程刚刚结束并且在堆栈上不可用。 @christianmini: 线程在堆栈上可用吗?那句话有问题 @Thomas。如果我在 UncaughtExceptionHandler 中设置断点,则主线程的堆栈(在 Eclipse 调试视图中可见)包含此调用作为叶子和 ThreadGroup.uncaughtException(Thread, Throwable) 作为根,但不包含导致异常的方法。 @christianmini:AFAIK,这对于未处理的异常处理程序是不可能的。我在 C++ 和 C# 中都没有看到过这种情况,所以我怀疑在 Java 中是否可行。我真的很想知道为什么打破“异常”和“可投掷”是不够的。隐藏了哪些异常?例如,在 C# 中,您无法捕获 ***Exception(可能还有更多)。 【参考方案1】:你可以先在Eclipse中验证这个设置是否启用。
窗口 -> 首选项 -> Java -> 调试 -> 对未捕获的异常暂停执行
如果启用此设置,任何未捕获的异常都将在 JVM 被抛出的那一刻暂停,包括使用反射调用的类。这是没有添加任何断点,但提供了它的未处理,即您的代码甚至不会被来自 try-catch 的外部代码调用。
例如
int a = 0, b= 0;
System.out.println(a/b); // ArithmeticException
即使这段代码是从反射调用代码中调用的,eclipse 也会在 sysout 处挂起,所有变量在堆栈上仍然可用。
但是在 Android 的启动类 ZygoteInit
中有这样一行:
catch (Throwable t)
Log.e(TAG, "Error preloading " + line + ".", t);
if (t instanceof Error)
throw (Error) t;
if (t instanceof RuntimeException)
throw (RuntimeException) t;
throw new RuntimeException(t);
此类代码会破坏 Eclipse 调试的原因是,RuntimeException
现在不再未处理。您的 UncaughtExceptionHandler
实际上可能正在捕获启动类而不是您的用户代码。这是用于常规 Eclipse。
解决方案 1:
-
转到运行 -> 添加 Java 异常断点 ->
Throwable
在断点视图中单击Throwable
右键->断点属性->添加包->确定
检查选项此异常的子类
注意:这可以勉强捕捉到java.lang.OutOfMemoryError
,但绝对不能捕捉到java.lang.***Error
。
解决方案 2:(仅当捕获的异常过多时,否则不推荐)
-
将
com.android.internal.os.ZygoteInit
的源代码复制到一个新项目比如MyBootstrap
修改catch (Throwable t)
块以仅捕获Error
catch (Error t)
Log.e(TAG, "Error preloading " + line + ".", t);
throw t;
转到调试配置 -> 类路径 -> 单击引导条目 -> 添加项目 -> MyBootstrap
。将此项目移至顶部
【讨论】:
我想你理解了这个问题:“RuntimeException 现在不再未处理”,所以我必须从所有 Java 运行时异常中选择父级,“Throwable”,并且我必须选择“Caught”位置” e “此异常的子类”。好的,唯一的问题是在一个Android应用程序的周期中,用户代码或SDK中有数百个Caught Exception,有没有办法过滤? @christianmini 那么在这种情况下,catch
不能是确定性的。删除catch (Throwable t)
以进行调试如何引导ZygoteInit
?由于此类用于启动并且不进行本机调用,因此对于调试应该没问题。这样,您未处理的异常仍然未处理。
好的,我也会更新答案以包括引导程序,以防不熟悉的人。【参考方案2】:
基本上,如果我对您的理解正确,您希望设置一个断点,如果该异常没有/以后不会被处理,则该断点将触发在引发异常的点。
如果这就是你的意思,那么你所要求的基本上是不可能的。
在抛出异常时,调试器无法判断异常是否会被捕获。
在捕获异常的点,从抛出点...到捕获点...的状态(即堆栈帧、变量等)将被丢弃。
Java 调试器 API 不支持调试器可用于此目的的“倒带和重放”机制。
在我看来,您能做的最好的事情是 1) 识别您怀疑没有被捕获的异常,2) 在其构造函数或合适的超类构造函数上设置断点,3) 找出一些过滤条件排除不感兴趣的情况,并 4) 单步执行代码以查看是否捕获到异常。
注意:异常可能在与其实例化的不同点被抛出或重新抛出,因此异常构造函数断点并不总是有帮助。但通常会。
【讨论】:
我认为很少有库有catch Throwable
出于真正的原因,但隐藏在深处,导致调试过程中出现这种歧义。可能是类似的通用案例应该去 Java/Exception 的 SO 文档。
我的答案没有谈到捕获异常。而且我想不出创建Throwable
实例的正当理由。
关于 SO 文档的建议......我们还没有任何关于 Java 调试技术的重要信息。 (除了一个关于如何读取堆栈跟踪的示例。)以上是关于Eclipse - 在 Android 应用程序上引发未处理的异常时中断用户代码的主要内容,如果未能解决你的问题,请参考以下文章
如何在没有 Gradle 的 Eclipse 中的 Android 项目上启用 multidex
如何在 Eclipse 构建的 Android 应用程序中删除屏幕上的键
Android NDK 创建可执行文件但未将其推送到设备上 (Eclipse)