调试您的应用
Android Studio 自带的调试程序让您能够对运行在 Android Emulator 或相连 Android 设备上的应用进行调试。有了 Android Studio 调试程序,您就可以:
- 选择用来调试应用的设备。
- 在您的 Java 和 C/C++ 代码中设置断点。
- 在运行时检查变量和对表达式求值。
- 捕获应用的屏幕截图和视频。
要开始调试,请点击工具栏中的 Debug。Android Studio 会构建一个 APK,用调试密钥签署它,将其安装在您选择的设备上,然后运行它并打开 Debug 窗口,如图 1 所示。如果您向项目添加 C 和 C++ 代码,Android Studio 还会在 Debug 窗口中运行 LLDB 调试程序来调试您的原生代码。
如果您点击 Debug 后 Select Deployment Target 窗口中未出现任何设备,则您需要连接设备,或点击 Create New Emulator 来建立 Android Emulator。
图 1. Debugger 窗口,显示变量的当前线程和对象树。
如果您的应用已运行在连接的设备或模拟器上,就可以按下述步骤开始调试了:
- 点击 Attach debugger to Android process。
在 Choose Process 对话框中,选择您想将调试程序连接到的进程。
默认情况下,调试程序显示当前项目的设备和应用进程,以及计算机上所有已连接的硬件设备或虚拟设备。选择 Show all processes 可显示所有设备上的全部进程;举例来说,显示的内容包括您的应用创建的所有服务以及系统进程。您可以从 Debugger 菜单中选择其他调试类型。默认情况下,Android Studio 使用 Auto 调试类型,根据您的项目包含 Java 还是 C/C++ 代码选择最适合您的调试程序选项。
点击 OK。
出现 Debug 窗口。在本例中,注意 Debug 窗口标题右侧的两个标签:一个标签用于调试原生代码,另一个用于调试 Java 代码(以 -java 表示)。
独立的调试会话具有独立的标签和不同的端口号(显示在标签内的括号中)。要结束调试会话,点击该会话的标签,然后点击 Terminate。
注:Android Studio 调试程序与垃圾回收器采用松散集成。Android 虚拟机可保证在调试程序断开连接后才会对调试程序发现的任何对象进行垃圾回收。这可能导致调试程序处于连接状态时对象累积过多。例如,如果调试程序发现某个运行中的线程,即便该线程已终止运行,系统也不会对关联的Thread
对象进行垃圾回收。
调试类型
默认情况下,Android Studio 使用 Auto 调试类型来决定使用哪个(些)调试程序,因此您在调试 Java 代码与调试 C/C++ 代码之间切换时不必更改配置。不过,您可以创建或编辑调试配置来自定义某些设置(例如添加符号目录或 LLDB 命令),或使用其他调试类型。您还可以在将调试程序连接到运行中的某个 Android 进程时从 Choose Process 对话框的 Debugger 下拉列表中选择调试类型。
有下列调试类型可供您选择:
- Auto
- 如果您希望 Android Studio 自动为您要调试的代码选择最合适的选项,请选择此类型。例如,如果您的项目包含任何 C 或 C++ 代码,Android Studio 会自动使用 Hybrid 调试类型。否则,Android Studio 会使用 Java 调试类型。
- Java
- 如果您只想调试以 Java 编写的代码,请选择此类型 - Java 调试程序会忽略您在原生代码中设置的任何断点或监视。
- Native
- 如果您只想使用 LLDB 来调试代码,请选择此类型。使用此调试类型时,Java 调试程序会话视图不可用。默认情况下,LLDB 只检查您的原生代码,而会忽略 Java 代码中的断点。如果您也想调试 Java 代码,则应切换到 Auto 或 Hybrid 调试类型。
- Hybrid
- 如果您想在调试 Java 代码与调试原生代码之间切换,请选择此类型。Android Studio 会将 Java 调试程序和 LLDB 都连接到您的应用进程,一个用于 Java 调试程序,一个用于 LLDB,这样一来,您不必重新启动应用或更改调试配置,便可同时对 Java 代码和原生代码中的断点进行检查。
注:Android Studio 提供了一项实验性 Java 识别 C++ 调试程序功能,让您能够利用单个 LLDB 进程同时调试 Java 和 C/C++ 断点。尽管该功能仍处于开发阶段,但您可以在 Android Studio 2.2 及以上版本中自行试用。如需了解更多信息,请访问 Android 工具网站。
使用系统日志
系统日志会在您调试应用时显示系统消息。这些消息包括运行在设备上的应用产生的信息。如果您想利用系统日志来调试应用,请确保您的代码能够在应用处于开发阶段时写入日志消息和打印针对异常的堆叠追踪。
在代码中写入日志消息
要在代码中写入日志消息,请使用 Log
类。日志消息可帮助您了解执行流程,它会在您与应用交互时收集系统调试输出。日志消息可以告诉您应用的哪个部分出现了故障。如需了解有关日志记录的详细信息,请参阅读取和写入日志。
下例展示了如何通过添加日志消息来确定您的 Activity 启动时先前状态信息是否可用:
- import android.util.Log;
- ...
- public class MyActivity extends Activity {
- private static final String TAG = MyActivity.class.getSimpleName();
- ...
- @Override
- public void onCreate(Bundle savedInstanceState) {
- if (savedInstanceState != null) {
- Log.d(TAG, "onCreate() Restoring previous state");
- /* restore state */
- } else {
- Log.d(TAG, "onCreate() No saved state available");
- /* initialize app */
- }
- }
- }
开发期间,您的代码还可以捕获异常并将堆叠追踪写入系统日志:
- void someOtherMethod() {
- try {
- ...
- } catch (SomeException e) {
- Log.d(TAG, "someOtherMethod()", e);
- }
- }
注:当您已准备好发布应用时,需要从代码中移除调试日志消息和堆叠追踪打印调用。您可以通过设置一个 DEBUG
标志并将调试日志消息放入条件语句来实现移除。
查看系统日志
Android DDMS (Dalvik Debug Monitor Server) 和 Android Monitor 窗口均显示系统以及任何特定应用进程产生的日志。要在 Android DDMS 工具窗口中查看系统日志,请执行以下操作:
- 按在调试模式下运行您的应用中所述启动您的应用。
- 点击 Android Monitor。
- 如果 Logcat 视图中的系统日志为空,点击 Restart。
图 2. Android DDMS 工具窗口中的系统日志。
您可以通过 Android DDMS 工具窗口访问 Android Studio 中提供的一些 DDMS 功能。如需了解有关 DDMS 的详细信息,请参阅使用 DDMS。
系统日志显示的消息来自 Android 服务以及其他 Android 应用。要过滤日志消息,只查看您感兴趣的内容,请使用 Android DDMS 窗口中的工具:
- 要只显示特定进程的日志消息,请在 Devices 视图中选择该进程,然后点击 Only Show Logcat from Selected Process。如果 Devices 视图不可用,请点击 Android DDMS 工具窗口右侧的 Restore Devices View。只有在您隐藏了 Devices 窗口时才会出现该按钮。
- 要按日志级别过滤日志消息,请从 Android DDMS 窗口顶部的 Log Level 下拉列表中选择一个级别。
- 要只显示包含特定字符串的日志消息,请在搜索框中输入字符串,然后按 Enter。
使用断点
Android Studio 支持使用若干类型的断点来触发不同的调试操作。最常见的类型是在指定代码行暂停应用执行的行断点。暂停时,您可以检查变量,对表达式求值,然后继续逐行执行,以确定运行时错误的原因。
要添加行断点,请按如下所述操作:
- 找到您想暂停执行的代码行,然后点击该代码行的左侧空白处,或将光标置于代码行上,然后按 Ctrl+F8(在 Mac 上,按 Command+F8)。
- 如果您的应用已处于运行状态,您不必更新应用便可添加断点 - 只需点击 Attach debugger to Android proccess。否则,请点击 Debug 开始调试。
图 3. 当您设置断点时,代码行旁会出现一个红点。
当您的代码执行到达该断点时,Android Studio 会暂停应用的执行。您可以随后使用 Debugger 标签中的工具来确定应用的状态:
要检查变量的对象树,请在 Variables 视图中将其展开。如果 Variables 视图不可见,点击 Restore Variables View。
要在当前执行点对某个表达式求值,点击 Evaluate Expression。
要前进到下一行代码(而不进入方法),点击 Step Over。
要前进到方法调用内的第一行,点击 Step Into。
要前进到当前方法之外的下一行,点击 Step Out。
要让应用继续正常运行,点击 Resume Program。
如果您的项目使用了任何原生代码,默认情况下,Auto 调试类型会将 Java 调试程序和 LLDB 两者都作为独立进程连接到您的应用,这样一来,您无需重新启动应用或更改设置,便可在检查 Java 断点与 C/C++ 断点之间进行切换。
注:要想让 Android Studio 检测到 C 或 C++ 代码中的断点,您需要使用支持 LLDB 的调试类型,例如 Auto、Native 或 Hybrid。您可以通过编辑调试配置来更改 Android Studio 使用的调试类型。如需了解有关不同调试类型的更多信息,请阅读有关使用其他调试类型的部分。
Android Studio 将您的应用部署到目标设备时,Debug 窗口打开时会为每个调试程序进程显示一个标签或调试会话视图,如图 4 所示。
图 4. 使用 LLDB 调试原生代码。
当 LLDB 调试程序遇到 C/C++ 代码中的断点时,Android Studio 会自动切换到 <您的模块> 标签。还会显示 Frames、Variables 和 Watches 窗格,其作用与您调试 Java 代码时完全相同。尽管 LLDB 会话视图中未出现 Threads 窗格,但您可以利用 Frames 窗格中的下拉列表访问您的应用进程。您可以在有关如何调试窗口框架和检查变量的部分详细了解这些窗格。
注:检查原生代码中的断点时,Android 系统会暂停运行应用的 Java 字节码的虚拟机。这意味着,在检查原生代码中的断点时,您无法与 Java 调试程序进行交互,或从 Java 调试程序会话检索任何状态信息。当 Java 调试程序遇到 Java 代码中的断点时,Android Studio 会自动切换到 <您的模块>-java 标签。
使用 LLDB 进行调试时,您可以利用 LLDB 会话视图中的 LLDB 终端向 LLDB 传递命令行选项。
提示:如果您想让 LLDB 在您每次开始调试应用时(在调试程序刚刚连接到您的应用进程之前或之后)执行某些命令,您可以将这些命令添加到您的调试配置中。调试 C/C++ 代码时,您还可以设置称作监视点的特殊类型断点,这类断点可以在您的应用与特定内存块进行交互时暂停应用进程。如需了解更多信息,请阅读有关如何添加监视点的部分。
查看和配置断点
要查看所有断点和配置断点设置,请点击 Debug 窗口左侧的 View Breakpoints。出现 Breakpoints 窗口,如图 5 所示。
图 5. Breakpoints 窗口列出了全部现有断点并包括每个断点的行为设置。
您可以通过 Breakpoints 窗口左侧的列表启用或停用每个断点。如果停用了某个断点,Android Studio 不会在应用遇到该断点时将其暂停。从列表中选择断点可配置其设置。您可以将断点配置为初始处于停用状态,让系统在遇到其他断点时将其启用。您还可以配置在遇到断点后是否应将其停用。要为任何异常设置断点,请在断点列表中选择 Exception Breakpoints。
调试窗口框架
在 Debugger 窗口中,Frames 窗格让您能够检查导致遇到当前断点的堆叠框架。这样,您就可以浏览和检查堆叠框架,同时还可以检查 Android 应用中的线程列表。要选择线程,请使用线程选择器下拉列表并查看其堆叠框架。点击框架中的元素会在编辑器中打开源代码。您还可以按窗口框架指南中所述自定义线程呈现和导出堆叠框架。
检查变量
在 Debugger 窗口中,Variables 窗格让您能够在系统将应用停止在某个断点处,并且您从 Frames 窗格选择某个框架时对变量进行检查。此外,Variables 窗格还能让您利用所选框架内提供的静态方法和/或变量对临时表达式求值。
Watches 窗格提供的功能类似,不同的是添加到 Watches 窗格的表达式可跨调试会话存留。您应该为自己经常访问或者提供的状态对当前调试会话有帮助的变量和字段添加监视。将出现如图 5 所示的 Variables 和 Watches 窗格。
要向 Watches 列表添加变量或表达式,请执行以下步骤:
- 开始调试。
- 在 Watches 窗格中,点击 Add。
在出现的文本框中,键入您想监视的变量或表达式的名称,然后按 Enter。
要从 Watches 列表移除某一项,请选择该项,然后点击 Remove。选择某一项,然后点击 Up 或 Down,可对 Watches 列表中的元素重新排序。
图 6. Debugger 窗口中的 Variables 和 Watches 窗格。
添加监视点
调试 C/C++ 代码时,您可以设置称作监视点的特殊类型断点,这类断点可以在您的应用与特定内存块进行交互时暂停应用进程。例如,如果您为某个内存块设置了两个指针并为其分配了一个监视点,则使用任一指针访问该内存块都会触发该监视点。
在 Android Studio 中,您可以通过选择特定变量在运行时创建监视点,但 LLDB 只会将该监视点分配给系统分配给该变量的内存块,而不会分配给变量本身。这与将变量添加到 Watches 窗格是不同的,在这种情况下,您可以观察变量的值,但当系统读取或更改其内存中的值时,您无法暂停应用进程。
注:当您的应用进程退出某个函数,并且系统从内存中释放其局部变量时,您需要重新分配为这些变量创建的所有监视点。
要设置监视点,您必须符合下列要求:
- 您的目标物理设备或模拟器使用 x86 或 x8664 CPU。如果您的设备使用 ARM CPU,则您必须将变量的内存地址边界分别按照 4 字节(对于 32 位处理器)或 8 字节(对于 64 位处理器)对齐。您可以通过在变量声明中指定
_attribute
((aligned(num_bytes)))
在原生代码中对齐变量,如下所示:
- // For a 64-bit ARM processor
- int my_counter __attribute__((aligned(8)));
您已经分配了不超过三个监视点。Android Studio 在 x86 或 x86_64 目标设备上最多只支持四个监视点。其他设备支持的监视点数量可能更少。
如果您符合上述要求,就可以按下述步骤添加监视点:将应用暂停于某个断点的情况下,导航至您的 LLDB 会话视图中的 Variables 窗格。
右键点击占据您想跟踪的内存块的变量,然后选择 Add Watchpoint。出现一个用来配置监视点的对话框,如图 7 所示。
图 7. 向内存中的变量添加监视点。使用下列选项配置您的监视点:
- Enabled:如果您想指示 Android Studio 暂时忽略该监视点,可以取消选择此选项。Android Studio 仍会保存您的监视点,以便您稍后在调试会话中访问。
- Suspend:默认情况下,Android 系统会在其访问您分配给监视点的内存块时暂停应用进程。如果您不需要此行为,可以取消选择此选项 - 取消选择时会出现一些附加选项,您可以利用这些选项来自定义系统与监视点进行交互时的行为:Log message to console 和 Remove [the watchpoint] when hit。
- Access Type:选择当您的应用尝试对系统分配给变量的内存块执行读取或写入操作时是否应触发您的监视点。要在执行读取或写入操作时触发您的监视点,请选择 Any。
点击 Done。
要查看所有监视点并配置监视点设置,请点击 Debug 窗口左侧的 View Breakpoints。出现 Breakpoints 对话框,如图 8 所示。
图 8. Breakpoints 对话框列出了您的现有监视点,并包括每个监视点的行为设置。在您添加监视点后,点击 Debug 窗口左侧的 Resume Program 可继续执行应用进程。默认情况下,如果您的应用尝试访问您设置了监视点的内存块,Android 系统会暂停您的应用进程,您的应用最后执行的那行代码旁会出现一个监视点图标 (),如图 9 所示。
图 9. Android Studio 会指示应用在即将触发监视点之前执行的那行代码。
跟踪对象分配
Android Studio 允许您跟踪分配到 Java 堆上的对象,以及查看分配这些对象的类和线程。这样一来,您就可以查看在所关注时期分配的对象列表。这些信息对评估可能影响应用性能的内存使用极具价值。
- 按在调试模式下运行您的应用中所述启动您的应用,然后选择 View > Tool Windows > Android Monitor(或点击窗口栏中的 Android Monitor)。
- 在 Android Monitor 窗口中,点击 Monitors 标签。
- 在窗口顶部,从下拉列表中选择您的设备和应用进程。
- 在 Memory 面板中,点击 Start Allocation Tracking。
- 在设备上与您的应用交互。
- 再次点击同一按钮以停止分配跟踪。
Android Monitor 显示有关应用内存、CPU、GPU 和网络使用情况的信息。请参阅 Android Monitor 基础知识中有关如何使用 Android Monitor 的信息。另请参阅 Android Monitor 概览中对 Android Monitor 功能的介绍,其中包括日志记录目录 (logcat)、性能监视器、数据分析工具以及屏幕和视频拍照工具。
图 10.Android Studio 中的对象分配跟踪。
查看和更改资源值显示格式
在调试模式下,您可以查看资源值和选择其他显示格式。在显示了 Variables 标签并选择了框架的情况下,执行以下操作:
- 在 Variables 列表中,右键点击资源行的任意位置以显示下拉列表。
在下拉列表中选择 View as,然后选择您想使用的格式。
可供选择的格式取决于所选资源的数据类型。您看到的可能是一个或多个下列选项:- Class:显示类定义。
- toString:展示字符串格式。
- Object:显示对象(类实例)定义。
- Array:以数组格式显示。
- Timestamp:按以下格式显示日期和时间:yyyy-mm-dd hh:mm:ss。
- Auto:Android Studio 根据数据类型选择最合适的格式。
- Binary:显示使用 0 和 1 表示的二进制值。
- MeasureSpec:从父项传递给选定子项的值。请参阅
MeasureSpec
。 - Hex:显示为十六进制值。
- Primitive:显示为使用原语数据类型表示的数值。
- Integer:显示
Integer
类型的数值。
您可以按以下步骤创建自定义格式(数据类型渲染器):
右键点击资源值。
- 选择 View as。
- 选择 Create。出现 Java Data Type Renderers 对话框。
- 按照 Java 数据类型渲染器中的说明操作。
分析运行时指标以优化您的应用
即使您的应用未产生运行时错误,也并不意味着它不存在问题。您还应考虑下列问题:
- 应用对内存的使用是否高效?
- 应用是否产生了不必要的网络流量?
- 您应该重点关注哪些方法来改善应用的性能?
- 用户接听来电或收到消息时应用的行为是否正常?
Android 设备监视器是一个具有图形界面的独立工具,适用于若干 Android 应用调试和分析工具,包括 Dalvik Debug Monitor Server (DDMS)。您可以利用 Android 设备监视器分析内存使用情况,对方法进行性能分析,监视网络流量以及模拟来电和传入消息。
要在 Android Studio 中打开 Android 设备监视器,请点击工具栏上的 Monitor。Android 设备监视器在新窗口中打开。
如需了解有关 Android 设备监视器和 DDMS 的详细信息,请参阅设备监视器和使用 DDMS。
捕获屏幕截图和视频
Android Studio 让您能够在应用运行时捕获设备屏幕的截图或简短视频。屏幕截图和视频是有用的应用宣传材料,并且您还可以将它们附加在发送给开发团队的错误报告上。
要捕获应用的屏幕截图,请执行以下操作:
- 按在调试模式下运行您的应用中所述启动您的应用。
- 点击 Android Monitor。
- 点击左侧的 Screen Capture。
- 可选步骤:要在屏幕截图周围添加设备框架,点击 Frame screenshot。
点击 Save。
要为应用录制视频,请执行以下操作:按在调试模式下运行您的应用中所述启动您的应用。
- 点击 Android Monitor。
- 点击左侧的 Screen Record。
- 点击 Start Recording。
- 与您的应用交互。
- 点击 Stop Recording。
- 输入录制内容的文件名,然后点击 OK。