使用 Android Studio 中的调试程序

1. 准备工作

在此 Codelab 中,您将学习如何使用 Android Studio 中的调试程序来检查 Dice Roller 应用在运行时会发生什么。

调试程序是一个重要的工具,可让您检查为 Android 应用提供支持的代码的执行情况,以便修复其中的所有 bug。借助该工具,您可以指定何时暂停代码执行,并与变量、方法和代码的其他方面进行手动交互。

前提条件

学习内容

  • 如何将调试程序连接到 Android 应用。
  • 如何在连接了调试程序的情况下启动应用。
  • 如何使用调试程序的一些基本功能。
  • 调试程序通常有什么用途。

所需条件

  • 一台安装了 Android Studio 的计算机
  • Compose 中 Dice Roller 应用的解决方案代码

2. 观看配套代码演示视频(可选)

如果您想要观看某位课程讲师完成此 Codelab 的过程,请播放以下视频。

建议将视频全屏展开(使用视频右下角的 此符号显示了一个方形,其中的 4 个角是突出显示的,表示全屏模式。 图标),以便更清楚地查看 Android Studio 和相关代码。

这是可选步骤。您也可以跳过视频,立即开始按照此 Codelab 中的说明操作。

3. 获取起始代码

首先,请下载代码:

或者,您也可以克隆代码的 GitHub 代码库:

$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-dice-roller.git
$ cd basic-android-kotlin-compose-training-dice-roller

您可以在 GitHub 仓库中浏览代码。

4. 运行调试器

您可以通过以下两种方式将调试程序与应用一起运行:

  • 将调试程序连接到在设备或模拟器上运行的现有应用进程。
  • 在连接了调试程序的情况下运行应用。

无论采用哪种方式,均可在一定程度上实现相同的效果。熟悉这两种方式后,您可以选择您喜欢的方法,也可以视需要选择任一方法。

将调试程序连接到应用进程

如果您的应用已在运行,您可以将调试程序连接到该应用。

如需将调试程序连接到应用进程,请按以下步骤操作:

  1. 点击 5e037ad7aaa36799.png Run ‘app'

点击“run app”按钮以运行应用

  1. 应用在设备或模拟器上运行后,点击 b53445df2e1bec63.png Attach Debugger to Android Process

将调试程序连接到正在运行的应用

此时将打开 Choose Process 对话框,您可以从中选择要连接调试程序的进程。

  1. 选择 com.example.diceroller,然后点击 OK

选择要连接调试程序的进程

Android Studio 底部会显示 Debug 窗格,其中包含一条消息,指出调试程序已连接到目标设备或模拟器。

调试程序已连接到正在运行的进程

您已将调试程序连接到您的应用!无需担心这意味着什么,亦或是您可以使用调试程序执行哪些操作,此 Codelab 稍后将对此进行介绍。接下来,您将了解如何启动连接了调试程序的应用。

连接了调试程序的情况下运行应用

如果您从一开始就确定要使用调试程序,可以在连接了调试程序的情况下运行应用,这样能节省一些时间。此外,如果您想调试仅在应用启动时才运行的代码,则需要在连接了调试程序的情况下启动应用。

如需在连接了调试程序的情况下运行应用,请按以下步骤操作:

  1. Debug 窗格中,点击 930a4556994d2c41.png Stop 'Android Debugger',然后在设备或模拟器上关闭应用。

停止运行 Android 调试程序

  1. 点击 a4737e06791f5bbf.png Debug 'app'

在连接了调试程序的情况下运行应用

Android Studio 底部也显示相同的 Debug 窗格,其中包含一些控制台输出。

“Debug”窗格

现在,您已了解如何启动调试程序!接下来,您将了解如何使用调试程序。

5. 使用调试程序

Debug 窗格

您可能已经注意到,Debug 窗格顶部有不少按钮,但这些按钮现在意义不大,大多数按钮呈灰显状态,无法点击。本部分将介绍调试程序中的常用功能。对于其他按钮,此 Codelab 会在与所学知识相关时进行介绍。

首次启动调试程序时,您会在 Debug 窗格中看到多个按钮。在 Debug 窗格的顶部,您会看到 DebuggerConsole 按钮。

调试程序控件和控制台

Console 按钮会显示应用的 logcat 输出。如果您的代码中有任何日志语句,则该输出会在执行这段代码时显示。

Debugger 按钮会显示三个单独的窗格,这些窗格目前是空的,因为您未使用调试程序:

  1. Frames
  2. Variables
  3. Overhead

“Debugger”窗格包含 3 个部分

使用常用的调试程序功能

设置断点

调试程序的一个主要功能是,可让您使用断点让特定代码行停止执行。

如需在 Android Studio 中设置断点,您需要进入特定代码行,然后点击行号旁边的间距区域。如需取消设置某个断点,您需要点击间距区域中的现有断点以使其消失。

  • 如需自行尝试,请在设置 imageResource 变量的位置设置一个断点。

添加和移除断点

使用“Resume Program”按钮

在上一部分中,您在设置 imageResource 变量的位置设置了一个断点。该断点会导致执行在遇到此指令时暂停。使用调试程序暂停代码执行后,您可能需要继续执行,以便继续运行应用。为此,最直接的方法就是使用 Resume Program 按钮。

如需让程序继续运行,请按以下步骤操作:

  1. 点击 a4737e06791f5bbf.png Debug 'app'。应用启动后,您应该会看到如下图所示的内容:

fa27673a8e804aaf.png

在让程序继续运行之前,我们有必要对调试程序暂停执行时屏幕上显示的一些内容加以说明:

  • 现在,Debug 窗格中的许多按钮都是可点击的。
  • Frames 窗格会显示大量信息,其中会突出显示对设置了断点的代码行的引用。
  • Variables 窗格会显示许多项,但此应用的变量并不多,因此目前没有大量在此 Codelab 讨论范围内的相关信息。但是,检查变量是调试程序的一项重要功能,因为它可以反映代码在运行时发生的情况。稍后,此 Codelab 会详细介绍如何检查变量。

如果您在设备或模拟器上查看应用,就会发现屏幕是空白的,因为应用在一行代码处暂停运行了。更具体地说,就是执行在断点处停止了,并且界面尚未呈现。

请注意,仅仅是设置了断点,并不一定能让应用立即停止运行。这取决于您在代码中放置断点的位置。在本例中,您将断点放置在了应用启动时执行的代码行中。

切记,只有在尝试执行设置了断点的代码行时,应用才会在断点处暂停运行。您可以通过多种方式让调试程序继续运行,但目前您要使用 Resume Program 按钮。

  1. 点击 f4e16fbb7cdb8b2f.png Resume Program

“Resume”按钮

现在,您应该会看到如下图所示的内容:

应用运行时的“Debugger”窗格

大部分信息都会消失,按钮也会重新变为无法点击的状态。在您的设备或模拟器上,应用也会照常显示。这是因为代码在断点处已不再处于暂停状态,并且应用处于正常运行状态。调试程序已连接,但在尝试执行设置了断点的代码行之前,它不会执行很多操作。请保留该断点,因为它在后面的示例中有用。

使用“Step Into”按钮

借助调试程序的 Step Into 按钮,您可以非常方便地在运行时深入探究代码。如果某个指令调用了方法或其他代码段,您可以通过 Step Into 按钮进入相应代码,而无需在启动调试程序以设置断点之前手动进入相应位置。

如需使用 Step Into 按钮,请按以下步骤操作:

  1. MainActivity 类的 onCreate() 函数的 setContent lambda 正文(此处会调用 DiceRollerApp() 函数)中创建一个断点。

在第 44 行添加的断点

  1. 点击 a4737e06791f5bbf.png Debug ‘app' 以在连接了调试程序的情况下重新运行应用。执行会在调用 DiceRollerApp() 函数的代码行处暂停。
  2. 点击 step into Step Into

“Step Into”按钮

现在,系统会突出显示第 52 行,Debug 窗格中的 Frames 窗格也会指示代码已在第 52 行暂停。

应用在第 52 行暂停

如果展开 Frames 窗格,您会看到突出显示的代码行后面的代码行以 invoke: 开头,后跟行号(即上一张图片中的“44”)。这称为“调用堆栈”。实质上,它显示的是引导代码执行到当前代码行的调用链。在本例中,第 44 行存储了用于调用 DiceRollerApp() 函数的指令。

当调试程序在相应函数调用中设置的断点处停止时,如果您点击 Step Into 按钮,调试程序会步入到相应函数,这会导致系统执行第 52 行代码(即声明该函数的位置)。突出显示的代码行指示了执行暂停的位置。如果突出显示的代码行后面的各行代码有关联的行号,则表示执行路径。在本特定示例中,调试程序会指示第 44 行中的指令已让您进入第 52 行。

  1. 点击 edb3c56acaffc23e.png Resume Program

这应该会引导您前往您设置的原始断点。您或许能够进一步了解您在第一个示例中停止执行时看到的内容。下图与 Resume program 部分中第 6 步的图片相同:

点击“Resume”以继续

在调用堆栈中,您可以看到 DiceWithButtonAndImage() 函数在第 63 行暂停执行,并且该函数是从第 44 行所调用的 DiceRollerApp() 函数的第 53 行调用的。借助调用堆栈功能,您可以了解执行路径。如果应用中的许多不同位置都会调用某个函数,函数堆栈非常有用。

借助 Step Into 按钮,您可以进入某个函数并暂停执行,而无需在函数本身内设置断点。在本例中,您是在对 DiceRollerApp() 函数的调用中设置了断点。当您点击 Step Into 按钮时,执行会在 DiceRollerApp() 函数中暂停。

Dice Roller 是一款相当小的应用,因为文件、类或函数的数量都不多。当您处理大型应用时,调试程序的 Step Into 功能会变得更加实用,因为借助该功能,您可以详细展开代码,而无需自行浏览代码。

使用“Step Over”按钮

借助 Step Over 按钮,您可以通过另一种方式在运行时逐步检查应用代码。它会将执行移至下一行代码,然后让调试程序继续执行。

如需使用 Step Over 按钮,请按以下步骤操作:

  • 点击 311eb654b5f218fd.png Step Over

“Debug”窗格中的“Step Over”按钮

现在,您会看到调试程序在执行下一代码行(即第 53 行)时暂停代码执行。您可以依次逐步检查每行代码。

代码在第 53 行暂停

使用“Step Out”按钮

Step Out 按钮的作用与 Step Into 按钮相反。Step Out 按钮会在调用堆栈中上移,而非展开调用堆栈的细目。

如需使用 Step Out 按钮,请按以下步骤操作:

  1. 点击 496d9a62300a4d97.png Step Out

您能否猜出程序会在哪个代码行暂停?

“Debug”窗格中的“Step Out”按钮

  1. 请注意,在 DiceRollerApp() 函数执行第 45 行后,调试程序单步退出了该函数,并单步进入了下一代码行。单步退出并不会返回第 44 行,因为该代码行已经执行。因此,单步退出会让您进入第 45 行。

单步退出会继续执行第 45 行

当您发现自己在方法调用堆栈中的位置过深时,Step Out 按钮是一个非常有用的工具。借助该按钮,您可以在调用堆栈中逐步上移,无需逐步检查您单步进入的每个方法的所有代码。

检查变量

此 Codelab 前面的部分简要介绍了 Variables 窗格,该窗格更深入地说明了如何检查其中所示的变量,帮助您调试应用中的问题。

如需检查变量,请按以下步骤操作:

  1. 点击断点以将其从调用 DiceRollerApp() 函数的位置移除,但应将断点保留在设置 imageResource 变量的位置。
  2. 点击 a4737e06791f5bbf.png Debug 'app'。您应该会看到,result$delegate 变量处于 MutableState 并且值为 1。这是因为,在定义该变量时,系统将其实例化为值为 1 的 mutableStateOfMutableState 表示结果变量具有可以更改的状态。

ee70fcf0cc18f4d7.png

  1. 点击 edb3c56acaffc23e.png Resume Program
  2. 在应用中,点击 Roll。您的代码将再次在断点处暂停,并且您可能会看到 result$delegate 变量变为其他值。

在此图中,result$delegate 变量的可变状态值为 6,演示了您可以如何使用调试程序在运行时检查变量。在功能更齐全的应用中,变量的值可能会导致崩溃。使用调试程序检查变量时,您可以更深入地了解崩溃详情,从而修复 bug。

d77800dd66311294.png

6. 总结

恭喜!您使用了 Android Studio 中的调试程序。

总结

  • 将调试程序连接到应用。
  • 在连接了调试程序的情况下启动应用。
  • 熟悉调试程序窗格。
  • 设置断点。
  • 从调试程序继续运行程序。
  • 使用 Step Into 按钮。
  • 使用 Step Over 按钮。
  • 使用 Step Out 按钮。
  • 使用调试程序检查变量。