一、起因
高级IDE的Debug功能几乎是必备的,我用的第一个Debug的IDE是Visual Studio(简称VS),那时还是大学。工作之后其实大多数时间开发的是业务为导向的app,调试的几乎也就是看看某些执行流程对不对,或者某些变量的动态值,这些app大多面向网络的,大多数是调试网络接口,用Charles抓包然后加打印Log的方式就可以了。但最近研究AndroidFramework层的功能,简单的调试已经不能满足了,举个简单的例子,Android源码调试,总不能每次加一行Log然后编译一次系统吧=_=
二、从何说起
1. 如何打断点
好像所有的IDE,打断点的方式没什么区别吧,就是行号旁边点击一下,看下图:
上图中的断点有三个,分别是Java Field Watchpoints
Java Line Breakpoints
Java Method Breakpoints
,还有几种断点,没法在界面中显示出来。要想看项目中的所有的代码,可以打开Breakpoints控制面板:菜单栏 Run -->View Breakpoints
如下图所示:
看左侧的列表分类,断点类型大概总共六类如下表:
断点名字 | 中文名字 | 作用 |
---|---|---|
Java Line Breakpoint | 行断点 | 最常见的断点,执行到这一行代码会触发断点 |
Java Method Breakpoint | 方法断点 | 断点打在方法头那一行,更加方便的观察参数和返回值 |
Java Field Breakpoint | 字段断点 | 打在某个字段声明上,当字段被重新赋值的时候触发断点 |
Java Exception Breakpoint | Java 异常断点 | 当抛出某个异常时,触发断点 |
Exception Breakpoint | 异常断点 | 未知 |
Symbolic Breakpoint | 符号异常 | 未知 |
看我左边看右边,右边是对每个断点的详细配置,以行断点为例,其余大同小异(出了上表最后两个):
- Enable:断点是不是可用
- Suspend:执行到断点的时候,程序是不是暂停到断点
- Condition:执行这个断点条件
- Log message to console :执行到这个断点的时候,打印一行日志
- Evaluate and log: 执行到这个断点时候,打印一样自定义日志,这个日志中可以包含程序中的变量或者求值表达式(很有用,这样可以省去一部分Log)
- Remove once hit:断点触发一次后就被移除了
其余的配置我也没用过,表示不会
2. 启动debugger
里面有几个按钮可以尝试都点一下,英文也很容易理解,从下面的进程中选择一个要attach 到debugger上,然后就可以debug这个进程了。启动之后,等到某个断点被触发的时候,就出现了下面的界面。同时可以选择调试类型,如下引自官网:
有下列调试类型可供您选择:
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 代码和原生代码中的断点进行检查
3. 调试工具窗口
启动调试之后调试面板如下图所示,看起来好复杂,全是按钮,把鼠标悬停在按钮上会出现这个按钮的名字:
先看控制按钮,再看控制面板:
1). 横向控制按钮
如上图,这些都是基本的单步调试工具所具有的功能,上面很重要的是那个Evaluate Expression
通过它可以查看当前类中所有的变量的值,并且可以计算表达式的值,甚至可以运行某个函数,得到结果。可以尝试下,在输入的时候有代码提示,比如在输入框输入我们上面的求和的函数,就能直接得到运行结果。
2). 竖向控制按钮
标号 | 名字 | 作用 |
---|---|---|
① | Rerun android debugger | 启动或者重启debugger |
② | resume program | 运行程序,到下一个断点处 |
③ | pause program | 暂停程序 |
④ | stop android debugger | 停止debugger,终止调试 |
⑤ | View Breakpoints | 打开断点设置面板,和从菜单栏Run-->view breakpoints 进入的是同一个 |
⑥ | Mute Breakpoints | 暂时停用所有的断点 |
7 | Get Thread dump | 获取某个进程的信息 |
⑧ | Restore Layout | 恢复原来的debugger控制面板的布局 |
⑨ | Settings | 设置在调试过程中,会显示那些信息(可以点开看看) |
10,11,12 | 固定窗口,关闭窗口,查看帮助 |
3). 调试工具窗口(或者说窗口)
名字 | 作用 |
---|---|
Console | 控制台,上面设置的断点的log比如Log message to console 就打印在这里 |
Frames | 正在运行的线程的堆栈信息(堆栈帧) |
Virables | 每个线程调用栈中的变量 |
Watches | 观察某个变量或者某个方法的执行结果(这个比较有用)通过点击Watches面板下边的加号可以添加要观察的对象 |
三、最后看个简单的例子
解读一下上面的配置:这个断点是一个行断点,打在了代码21行,目前断点有效(enable),当断点被触发的时候程序会停在断点处等待用户操作(Suspend),这个断点是有触发条件的,必须在for循环中i不等于0的情况下才会触发这个断点(Condition i!=0
),当断点触发的时候会在控制台打印一句log通知用户,断点被触发(Log message to console ),并且我们自定义个log,能够打印i+i 的值("计算下"+i+"+"+i+"="+calculate(i,i)
)。是不是真是这样呢,可以按照上面的步骤启动调试,然后点击按钮使其执行onClick方法,然后执行到这个for循环,看是否能够打印log。
运行结果如下:
其余类型断点,的配置和调试大同小异,可以点着玩 ̄□ ̄||
【参考文献】