小技巧 | 在 Android Studio 调试应用 (下)

小技巧 | 在 Android Studio 调试应用 (下)

作为开发者,我们有时会被一些问题所困,导致在调试器中所花费的时间甚至超过了编写代码所用的时间。正因如此,最近我们找机会了解了 Android Studio 团队在提升调试速度方面使用的一些技巧。接下来,我们会为您一一呈现那些我们认为最好的、节省您时间的、且方便与您的调试流程整合的小技巧。

 

虽然您的应用可能与本文假想中的示例应用大相径庭,但是本文所介绍的小窍门可以用在任何应用的开发上。本文分为上下两篇,上篇已于前段时间发布,如果您还没来得及阅读上篇,请在这里查看《在 Android Studio 中调试您的应用 (上)

Drop frame (丢弃当前帧)

有些时候,当您浏览挂起的代码时,可能会意外跳过某个本应该进入的方法。如果您的设备运行的是 Android 10 或者更高版本,您可以通过点击调试工具栏中的 Drop Frame 按钮来进行回溯:

小技巧 | 在 Android Studio 调试应用 (下)

这个功能会把您从当前的方法带回到其开始执行前的节点,从而给您一个重新进入该方法的机会。

 

此功能并不是 "时间机器"。如果您正处于一个长函数的中间位置,而它此前已经执行了许多工作 (例如,修改了当前类的状态)。在您丢弃当前帧时,这类操作所产生的改变不会被撤销。

Mark object (标记对象)

有时候,您会想要跟踪某些特定类型实例的生命周期。本例中,要跟踪的对象有一个哈希值: @10140:

小技巧 | 在 Android Studio 调试应用 (下)

为了能够在这个对象再次出现时可以认出它来,您可能已经掏出纸笔准备记下这个数字了。不过您也可以选择另一种方式: 右击该对象,点击 Mark Object 为其添加标签。

 

这样一来,无论被标记的对象出现在调试窗口的任何地方,它都会带有您添加的标签以方便辨认。这里我们为该对象添加一个 "myItem" 标签:

小技巧 | 在 Android Studio 调试应用 (下)

更棒的是,就算您处于完全不同的上下文,无法触及到刚才的对象,您也可以在 Watches 窗口对其进行查看。无论您处在什么位置,只要触发断点,就可以在 Watches 窗口添加后缀为 "_DebugLabel" 的标签 (不用担心自己会不记得后缀的内容,这里有自动补全):

小技巧 | 在 Android Studio 调试应用 (下)

现在,您可以在任何地方使用 Watches 窗口来观察该类型对象的状态。

 

您也可以将此功能与条件断点组合。举例来说,您可打一个断点,右击并为其设置一个条件来检查打了标签的对象:

小技巧 | 在 Android Studio 调试应用 (下)

这样一来,就不用在进入包含特定实例的范围之前跳过一堆断点,代码会运行到合适的地方再停止:

小技巧 | 在 Android Studio 调试应用 (下)

Evaluate expression (评估表达式)

尽管 VariablesWatches 窗口对于跟踪某个显式值时已经十分好用,但您有时候还是会想要更加*地探索您的代码,这时候就轮到评估表达式功能登场了。当您正处于某个断点时,您可以使用调试工具栏中的 Evaluate expression 按钮来访问这一功能。

小技巧 | 在 Android Studio 调试应用 (下)

您可以在 Expression 输入框中输入任何表达式,点击 Evaluate 按钮就可以对其进行评估。当然,如果您评估了一个对象,在评估完成后,您就可以在 Result 部分浏览该对象的详细信息:

小技巧 | 在 Android Studio 调试应用 (下)

评估表达式弹窗可能会以单行模式打开,您可以通过点击 Expand 来将其扩展为多行模式:

小技巧 | 在 Android Studio 调试应用 (下)

现在,您可以输入复杂的多行表达式,其中可以包含变量、if 语句等各种内容:

小技巧 | 在 Android Studio 调试应用 (下)

Apply changes

前面讲过,当您使用条件断点时,会需要评估一个表达式;即便代码没有在断点停止,调试器依然需要执行评估操作。如果您在一个非常紧密的循环中运行评估操作,例如游戏中的动画处理,则可能导致应用停顿。尽管条件断点很有用,但在某些情况下您可能无法依靠它们。

 

解决此问题的一种方法是将条件表达式添加到代码中,并使用无操作 (no-op) 表达式,从而使其可以附加断点:

小技巧 | 在 Android Studio 调试应用 (下)

在修改完代码之后,您可能会决定重启应用并点击 Debug 按钮,但是如果您的应用运行在 Android 8 或更高版本的系统中,您可以使用 Apply Code Changes

小技巧 | 在 Android Studio 调试应用 (下)

现在,嵌入的表达式已经修补了您的代码,但您仍然会在 Frames 窗口中看到您已经更新的方法被标记为过时 (Obsolete):

小技巧 | 在 Android Studio 调试应用 (下)

这是因为,虽然新的代码已经打好了补丁,但是调试器指向的仍是旧的代码。您可以使用丢弃当前帧的功能来离开旧的方法,然后进入修改过的方法之中。

 

尽管本例中并不需要,但这里还有一种选择: Apply Changes and Restart Activity。不同于 Apply Code Changes,该操作会重启 Activity。如果您修改了布局资源或您要调试的代码,例如在 onCreate 方法中,该选项将非常有用。

小技巧 | 在 Android Studio 调试应用 (下)

分析堆栈信息

就算您掌握了所有的窍门与技巧,您的代码仍然可能出现 Bug,而您也会因此收到一些崩溃报告,这些报告中则可能包含了异常堆栈信息的文本副本。您可以使用 Analyze 菜单中的 Analyze Stack Trace or Thread Dump 将这些信息转化为有意义的内容。

 

此工具提供了一个粘贴堆栈信息的文本框,不过它也会自动填充系统剪贴板中的文本:

小技巧 | 在 Android Studio 调试应用 (下)

点击 OK 之后,就会将包含完整注释的堆栈信息添加到控制台:

小技巧 | 在 Android Studio 调试应用 (下)

您可以一眼看出来自您自己代码文件的内容 (以蓝色突出显示) 与您可能不需要关注的代码 (以灰色突出显示)。并且,您可以通过单击链接在您的代码文件中进行跳转。

结语

本文提供了一些可以加快调试速度的技巧和窍门。由于篇幅所限,更多技巧简单归纳如下:

  • 在 Debug 模式下,点击代码的行数数字可以直接执行此行代码

  • Ctrl + 拖动操作可以复制断点

  • 您可以在函数的右括号处设置断点

  • 您可以在字段和属性上设置断点,被称为 "field watchpoints"

  • 您可以为接口中的方法设置断点,从而使它的所有实现都会触发断点

您可以通过下面这个视频再次回顾更多本文的细节和演示内容:

  • 腾讯视频链接

    https://v.qq.com/x/page/o3030ha9b5e.html

  • Bilibili 视频链接

    https://www.bilibili.com/video/av78114615/

也请您查阅更多与本话题相关的资源:

  • Android Developer 官方文档 | 调试预构建的 APK

    https://developer.android.google.cn/studio/debug/apk-debugger

  • 通过数据浏览来控制数据在调试器中的显示方式

    https://www.jetbrains.com/help/idea/debugger-data-type-renderers.html

  • 如何使用和理解 Overhead 选项卡

    https://www.jetbrains.com/help/idea/monitor-debugger-overhead.html

  • Android Developer 官方文档 | Android Studio — 调试您的应用

    https://developer.android.google.cn/studio/debug

  • IntelliJ IDEA 调试代码

    https://www.jetbrains.com/help/idea/debugging-code.html

小技巧 | 在 Android Studio 调试应用 (下)


推荐阅读

小技巧 | 在 Android Studio 调试应用 (下)

小技巧 | 在 Android Studio 调试应用 (下)

小技巧 | 在 Android Studio 调试应用 (下)

小技巧 | 在 Android Studio 调试应用 (下) 点击屏末  | Android Developer 官方文档 | Android Studio — 调试您的应用


小技巧 | 在 Android Studio 调试应用 (下)

小技巧 | 在 Android Studio 调试应用 (下)

小技巧 | 在 Android Studio 调试应用 (下)