逮虾户!Android程序调试竟简单如斯
PS:行吧,不用百度了,逮虾户是《头文字D》的一首配乐《Deja vu》,中文谐音
“逮虾户”,飙车漂移专用BGM,有时音乐响起也暗示着:开车。
当然本节讨论的不是开车,而是Android开发中老生常谈的程序调试。
一个开发仔的日常离不开:写BUG和解BUG,特别是多人协作的时候,
帮别人擦屁股(解Bug)的情况屡见不鲜。另外,接盘别人的项目,着手解
Bug也能帮你快速的上手项目。综上,修炼好「调试」这门技能显得尤为重要。
但是,但是感觉很多玩家还停留下无脑打印的阶段,所以有了这篇文章。
笔者尽量以最精简的方式来过一过Android调试中的常(qi)规(ji)操(yin)作(qiao)。
逮虾户~
1.无脑静态调试
解释下这个标题:
- 无脑:觉得哪里有问题,就打印哪里。
- 静态:每次想打印,都要去修改代码,然后重新运行程序。
适用于:想查看变量的值在某一时刻是否异常!
接着来说下两种常用的调试方法:
Toast打印法
新手Android开发仔最爱调试法,使用简便,仅需一行代码,轻松打印:
Toast.makeText(MainActivity.this, "Toast调试", Toast.LENGTH_SHORT).show();
方便是挺方便的,不过有一点要注意:Android 5.0后,如果把「消息通知的权限」
关闭掉的话,部分机型是不会显示Toast的!你还可以使用Snackbar来显示值进行调试:
Snackbar.make(父view, "Snackbar调试", Snackbar.LENGTH_SHORT).show();
或者其他变通的方法,比如在页面上添加一个TextView,把值直接显示在文本框上。
Log日志打印法
Toast调试是挺爽的,但是有两个问题:
- 1.想调试打印多个值的话,Toast会弹个不停,毕竟同一时刻只有「一个」Toast显示在前台;
- 2.Toast间隔一段时间后会消失,即使你设置了Toast.LENGTH_LONG;
可能你一走神,没来得及看调试的值,Toast就消失了。我们着实需要一种无需担心调试
结果消失的方法——「Log日志打印法」,就是利用Android系统提供的Log类,在调试
的地方,把日志打印到「Logcat控制台」上,使用方法也非常简单:
Log.d("TAG", "Log调试")
当代码执行到这一句的时候,就会在Logcat控制台打印调试信息,另外Logcat默认
会打印出所有的日志信息,我们可以做一些过滤来定位到我们调试的日志信息。
首先是:「日志类型」,Android支持6种日志类型,依次如下:
- Verbose:详细,所有类型的日志信息。
- Debug:调试,调试用的日志信息。
- Info:信息,正常使用时需要关注的日志信息。
- Warn:警告,可能有问题,但没发生错误的日志信息。
- Error:错误,运行时出现严重错误的日志信息。
- Assert:断言。
温馨提示:
不要上来就Error级别,我以前打Log全部用Log.e,原因是日志信息是红色的,好看…
结果被组长屌了一顿,o(TωT)o ,觉得颜色不好看,你可以按照下述的操作进行自定义。打开「Settings」-> 「Editor」->「Colors Scheme」->「Android Logcat」
选择日志类型,然后去掉勾选,然后点击选择颜色色值这是笔者配色方案,读者可以自行调整为喜欢的颜色:
- Assert:8F0005
- Debug:0070BB
- Error:FF0006
- Info:48BB31
- Verbose:BBBBBB
- Warning:BBBB23
设置后的配色如图所示:
行吧,知道可以通过Log类打印调试和自定义Logcat配色,顺带也提提「日志过滤」的姿势吧。
- 自定义Logcat日志头信息的显示内容:点击面板上的「Logcat Header」来设置日志头信息
可选设置内容如下:
右侧还可以「过滤日志信息」,支持正则,再右面是过滤特定日志的选项。
如果觉得还不够的话,可以点击最右侧的「Edit Filter Configuration」来配置一个自己的过滤器。
另外,还可以对进行「日志搜索」,鼠标点击Logcat中间区域获得焦点,Ctrl + F 调出
搜索工具栏,接着搜索相关的日志内容。
顺带提下Log类的一个容易忽略的小坑:
Log类只会打印4000个字符,超过部分不打印!!!
2.有脑动态调试法
其实就是用Android Studio提供的Debug模式来程序调试,相比起前面的
Toast打印法和Log日志打印法,稍微复杂一点,要点学习成本,还有动脑子,
最重要是可以动态调试,很多新手玩家貌似对这个都望而却步,其实不难,待我
带你九浅一深,em…由浅入深走一遭,来学学Android Studio Debug核心技巧。
1)基本的调试流程
一般的调试流程图如下所示:(核心就是下断点,单步调试,值跟踪)
2)下断点
先说说断点,不是张敬轩的《断点》,调试时的断点的作用是:
当程序执行到断点所在的代码时,会暂停应用程序的运行,线程被挂起,然后
可以通过调试器进行跟踪。
下断点的方式也很简单,点击某行代码的左侧,会出现如图所示的小红点。
这个小红点就是断点,而在AS中,又有着多种类型的断点,带你们过一遍吧:
- ① 行断点
就是上面这种,对特定行进行调试时用到,点击行所在的左侧边栏即可设置。
右键点击这个断点,会弹出如下所示的设置对话框:
如果你取消了Enabled勾选,断点就处于如图所示的禁用状态:
- ② 方法断点
如果你把断点下到一个方法前,断点就会变成这样:
这个就是方法断点,一般用来检查方法的「输入参数」与「返回值」。
- ③ 变量断点
有时我们对程序运行过程并不关心,而只关注某个变量的变化,可以在变量定义前加一个断点。
在程序运行过程中,如果该变量的值发生改变,程序会自动停下来,并定位到变量值改变的地方,供开发者调试。
另外,右键还可以设置断点,Watch面板有两个特有的选项,可按需勾选:
- Field access:字段被访问时触发断点。
- Field modification:字段被修改时触发断点。
- ④ 条件断点(断点设置Condition)
有时会有这样的场景:把断点打到循环体的中,我们只关心特定循环次数下的运行情况。
比如一个循环10次的循环体,我们想知道循环到第8次时的运行情况,如果你不知道
条件断点的话,你需要一直按「Run to Cursor」直到满足我们的条件。比如下面的代码:
我们想知道当i = 8的时候,sum为多少,你需要一直按「Run to Cursor」
按7次,直到i = 9位置,如果用条件断点,当循环体执行到某个条件才停下来,右键断点,输入如图所示的等式条件:
然后可以发现,程序直接跳到i=8的时候才挂起,非常方便。
- ⑤ 日志断点
调试的时候我们可以通过打印日志的方式来定位异常代码大概位置,以缩小引发问题的范围,然后
再使用断点精确定位问题。如果是普通的打印日志,我们需要等待重新构建程序,如果用「日志断点」
就避免这个无意义的等待。使用日志断点非常简单,右键断点,去掉「Suspend」的勾选,会出现
如下所示的弹窗,勾选「Evaluate and log」在此输入想输出的内容。
运行调试后,当执行到日志断点的时候可以看到控制台输出了对应的日志信息,而且程序正常运行,并不会挂起。
如果想查看更详细的信息,比如断点的位置和触发时的堆栈信息,可以勾选「“Breakpint hit” message」和「Stacktrace」,勾选后输出内容会变得更详细:
- ⑥ 临时断点
所谓的临时断点就是:触发一次后就自动删除的断点。设置的方法有两种:
- 1.光标移到想打点的行,点击菜单栏「Run」->「Toggle Temporary Line Breakpoint」,
等价于快捷键:「Ctrl+Alt+Shift+F8」 - 2.更便捷的操作:按住Alt,鼠标点击左侧边栏。
鼠标点击后可以去掉临时断点,如果想把临时断点变成普通断点,可以取消勾选
「Remove once hit」的选项。
- ⑦ 异常断点
用于监听程序异常,一旦程序奔溃,直接定位到异常所在的确切位置。依次点击:
「Run」->「View Breakpoints」打开断点视图。点击「+」,然后选择
「Java Exception Breakpoints」,在弹出的窗口中输入要调试的异常:
除了设置异常断点外,你在这里看到项目设置的所有断点,并进行断点管理与配置。
另外,你还可以设置自定义异常断点,点击「4.Exception Breakpoints」自行配置即可。
3)进入调试模式的另一种方式
大部分的同学调试都是通过点击下面这个只小虫子进入调试模式。
这种方法有个缺点就是:每次都需要重新运行程序,可能有这样的场景:把APP丢给测试
测试,然后出现了一个很稀有的BUG,此时你如果用普通的Debug模式,需要重启APP,但是
Bug不一定能够复现,这就很尴尬了。对于需要动态调试的场景,可以「直接调试正在运行的
Android进程」,点击如下所示的另一个有小虫子的图标:
然后选择要调试的包名,就可以无需重启应用直接进行调试了:
4)调试工具详解
这里把调试工具划分为如图所示的五个区域一个个讲解:
- A区(步进调试工具)
图标 | 名称 | 功能描述 |
---|---|---|
显示执行点 | 定位到当前正在调试的断点。 | |
单步跳过 | 一步一步执行,遇到方法直接执行完方法,进入下一步,不会进入方法内部。 | |
单步进入 | 一步一步执行,遇到方法且是自定义的方法,则进入方法内部,否则不会进入。 | |
强制进入 | 遇到方法无论是自定义的还是官方类库的,都会进入方法内部。 | |
单步跳出 | 跳出当前进入的方法,返回方法调用处的下一行(也意味着方法被执行完毕)。 | |
丢弃帧 | 如果你在某个方法内,执行完丢弃帧,当前方法会被中断,返回方法被调用的 地方,变量的值也会重置。 | |
执行到光标处 | 可以看做是临时断点,程序运行到当前光标所在行暂停。 | |
计算表达式 | 支持在调试过程中,通过赋值或表达式方式修改任意变量的值。 |
!!!注意:上面的执行到光标处是有个前提的:中途没有断点,如果你想强制执行到
光标处的话,你需要「Force Run to Cursor」,你可以通过下述两种方式进行操作:
- 1.光标处右键,选中「Force Run to Cursor」,如图:
- 2.使用快捷键:Ctrl + Alt + F9。
- B区(控制调试工具)
图标 | 名称 | 功能描述 |
---|---|---|
继续程序运行 | 程序运行到某个断点暂停,如果有下一个断点,点击后跳到这个断点, 没有的话,程序则继续运行。 | |
暂停程序运行 | 暂停程序运行。 | |
终止程序运行 | 终止程序运行。 | |
查看断点 | 可以查看所有的断点,管理与断点配置 | |
禁用所有断点 | 切换所有断点的状态(启用/禁用),禁用后,程序就不会触发断点。 | |
获得线程堆栈 | 显示线程的相关信息 | |
恢复布局 | 恢复到原始布局 | |
设置 | 调试的相关配置,比如是否显示执行方法后的返回值 |
- C区(帧调试窗口)
这里的帧指的是:堆栈帧,一种用于「存储数据」和「部分过程结果」的数据结构;
每次调用方法在堆栈中都会占用一部分内存,单位是帧,随着方法调用而创建。
每个堆栈帧中包括了:「传入参数」、「返回地址」、「局部变量」以及「对程序调试提供支持的信息」。一个线程包括多个堆栈帧。
查看工具那里可以以上下顺序切换的方方式查看帧(鼠标直接点击也可以),最右侧的漏斗图标
点击后可以过滤掉:「非本应用的帧」。另外,你还可以右键堆栈帧,添加「步进过滤器」、
「导出线程」或「自定义线程显示」。
- D区(变量区)
在这个区域可以看到堆栈帧中当前所有的数据(方法参数、本地变量、实例变量)。
右键某个变量,可以进行「设置\复制变量值」,「跳转到变量在代码中的位置」等操作。
一个常用的操作:选择**「Add to Watches」**,单独监视这个变量的变化。
- E区(监视窗口)
除了前面这种右键添加监视的方法外,你还可以直接在E区点击「+」进行添加。
不止监控变量,还支持监控表达式,比如上面的i+1。
关于Android Debug调试的基本操作大概就这些,多去实战中历练巩固吧!
3.Android Wifi 无线调试
其实还是要先电脑这个也非常简单,安装一个「ADB WIFI」的插件,安装后重启:
然后把APP的调试模式为「Usb Device」
手机连接电脑,依次点击AS的菜单栏:「Tools」->「ADB USB TO WIFI 」,然后左下角会出现:
一般来说,要扫描好久,建议自己看下手机ip,然后通过adb命令进行链接,示例如下:
adb connect 10.1.7.200:5555
# 出现下述信息代表连接成功:
connected to 10.1.7.200:5555
连接成功后就可以拔掉数据线,进行无线调试了。
4.利用Network Profiler抓包
Android Profiler是AS 3.0后引入的性能分析工具,而Network Profiler是其中一个用于网络分析的工具,
利用它我们直接抓包,而不需借助第三方的抓包工具(比如Charles)进行分析调试。
比较简单,界面如下:
利用它可以进行很方便的抓包操作。
关于Android程序调试的东西肯定不止这些,上述的算是基本功吧。
有更多调试技巧欢迎在评论区留言~谢谢
参考文献:
Tips:公号目前只是坚持发早报,在慢慢完善,有点心虚,只敢贴个小图,想看早报的可以关注下~