简介
此种调试方式是通过
冻结应用运行的状态,仿佛时间停止了一般,然后我们逐一
观察此时程序的各个参数是否符合我们的预期。
这种调试方法
适用于对时间不敏感的程序。也就是说被调试的程序线程不需要依赖别的线程,即使暂时停止工作也不会影响别的工作线程或者受别的工作线程影响。
在希望代码
暂停运行的地方打断点,在代码前点击一下,出现一个红色的圆点,如果想取消,再点击一次即可。
点击顶部工具栏图标
开启调试模式
![795730-20180106200525753-1115321907.png](https://i-blog.csdnimg.cn/blog_migrate/8ae0bf4a979a226dba0b9a263e11d8cc.png)
点击左侧行号
红点位置
添加或取消断点
![795730-20180106200526003-609647156.png](https://i-blog.csdnimg.cn/blog_migrate/9e5795ac26a9f2cdef2d1e7fb2a2170a.png)
Frame区域是程序的
方法调用栈区,这个区域中显示了
程序执行到断点处所调用过的所有方法,越下面的方法被调用的越早。
由此顺序可了解Android系统启动流程,也即是怎么一步步调用到Activity的onCreate方法的:
![795730-20180106200526362-57695882.png](https://i-blog.csdnimg.cn/blog_migrate/360cacf56f185eea72e7e268aec4d731.png)
基本操作:常用工具栏
![795730-20180106200526643-793681377.png](https://i-blog.csdnimg.cn/blog_migrate/20da55ce68c031cd56b1cf55444336a9.png)
调试时的正确姿势是:
如果想一步步监测程序的运行过程,就一直点击【step over】
如果只想监测运行到某几行关键代码时的状态,就设置多个断点,然后一直点击【run to cursor】
如果想看看某个方法里面的运行过程,就点击一次【step into】或【force step into】
如果想跳出这个方法,就点击一次【step out】
1
如果想一步步监测程序的运行过程,就一直点击【step over】
2
如果只想监测运行到某几行关键代码时的状态,就设置多个断点,然后一直点击【run to cursor】
3
如果想看看某个方法里面的运行过程,就点击一次【step into】或【force step into】
4
如果想跳出这个方法,就点击一次【step out】
step over【一步步往下走】
程序向下执行一行,如果当前行有方法调用,这个
方法将被执行完毕返回,然后到下一行。
例如,当前程序走到了断点处:
![795730-20180106200526924-1387353856.png](https://i-blog.csdnimg.cn/blog_migrate/051d0dd9a32a7d5874790f212915f683.png)
此时点击step over后:
![795730-20180106200527112-1908757687.png](https://i-blog.csdnimg.cn/blog_migrate/c21090a5acacf076e682acffe8c85011.png)
再点击
step over后:
![795730-20180106200527315-1745628570.png](https://i-blog.csdnimg.cn/blog_migrate/084c8de50dc9f80caf4f66fef9500bca.png)
再点击
step over后(注意没有进入 stepNext 方法):
![795730-20180106200527518-1358452683.png](https://i-blog.csdnimg.cn/blog_migrate/ed89f9250826c84c8638190720c3b9ba.png)
再点击
step over后:
![795730-20180106200527737-474319968.png](https://i-blog.csdnimg.cn/blog_migrate/27adca0f6568380e55282b7a1ea0c110.png)
注意:如果 stepNext 方法中有断点,则点击step over后也会跳到 stepNext 方法中。
step into【看到方法往里走】
程序向下执行一行,
如果该行有自定义方法,则运行进入自定义方法(不会进入官方类库的方法)。
当前程序走到了断点处后点击step into后:
![795730-20180106200527924-2006699241.png](https://i-blog.csdnimg.cn/blog_migrate/b3f81c59b1eaddfdb13545975cea4757.png)
再点击step into后(进入了 Log.
i 方法):
![795730-20180106200529128-677459601.png](https://i-blog.csdnimg.cn/blog_migrate/b35c640725f70c8aca2ee0636ec3b981.png)
再点击step into后:
![795730-20180106200529331-964603656.png](https://i-blog.csdnimg.cn/blog_migrate/6b5ea6cda224507fa3b1a9ca9900d25f.png)
再点击step into后(进入了 stepNext 方法):
![795730-20180106200529909-1005363083.png](https://i-blog.csdnimg.cn/blog_migrate/64194cc4ba5428dd46382f4dff59d254.png)
再点击step into后(进入了 Toast.makeText 方法):
![795730-20180106200530534-1332414438.png](https://i-blog.csdnimg.cn/blog_migrate/6bb740aa5ab22071d06fd4c48981e2eb.png)
卧槽,你要是在进入 Toast.makeText 方法后不赶紧点击 step out 返回,后续将有上百次调用等着你。
force step into【所有方法看完整】
能进入任何方法,这个
可以看到你所调用的所有方法的实现,研究源码使用非常方便,平时使用不到。
step out【下一个断点或跳出方法】
1、如果在调试的时候你进入了一个方法,并觉得该方法没有问题,你就可以使用 step out 跳出该方法,
返回到该方法被调用处的下一行语句;
注意该方法已执行完毕。
2、如果后面有断点则走到下一个断点;如果后面没有断点,而是在一个调用的方法当中,则会跳出这个方法,并继续走。
比如,如果你只想监测所有value的值,只需设置如下一个断点,然后一直点击 step out 即可
![795730-20180106200532190-197825081.png](https://i-blog.csdnimg.cn/blog_migrate/bb365130a575f1c2f49f0f891a6078fe.png)
![795730-20180106200532846-1410056351.png](https://i-blog.csdnimg.cn/blog_migrate/ee7714ffbfca6c0e119afa955fea6136.png)
![795730-20180106200533128-1239599246.png](https://i-blog.csdnimg.cn/blog_migrate/63814a406c3f7de26cce558f2e754380.png)
当执行完循环后再点击 step out,程序会跳出 test 方法。
![795730-20180106200534393-1613190335.png](https://i-blog.csdnimg.cn/blog_migrate/47d53588bfbf2f6a49b311fa98f2399b.png)
run to cursor【下一个断点】
和 step out 中的【下一个断点】功能相同,但是因为功能专一,所以不容易出现莫名其妙的跳转。
drop frame【回退到上一个调用的方法】
返回到当前方法的调用处重新执行,并且所有上下文变量的值也回到那个时候。
只要调用链中还有上级方法,可以跳到其中的任何一个方法。
所谓的Frame,其实对应的就是一次方法调用压栈的信息。
其他操作
![795730-20180106200535221-1901243657.png](https://i-blog.csdnimg.cn/blog_migrate/717cf9bff59045fe14d9ea606bf178a2.png)
resume program:程序继续往下执行,直到遇到下一个断点(感觉和 run to cursor 没任何区别呀)
pause
program:程序暂停往下执行
stop app:停止调试,App会关闭,你再次打开时不再是调试模式
view breakpoints:查看所有设置的断点及其位置,也可以设置断点的一些属性
mute
breakpoints:暂时使所有断点失效
get thread dump:获取线程堆栈信息
restore layout:恢复调试版本为默认的布局
Variables 变量面板
1、直接
在代码中就可以看到代码执行到当前位置时各个变量的值
2、
在Variables面板中也能查看
![795730-20180106200535549-2007129423.png](https://i-blog.csdnimg.cn/blog_migrate/6923e1273929b6a4b43306c1a9f98dc5.png)
左边几个图标代表的功能分别是:添加、删除变量,上下移动变量的位置,复制(duplicate),将要观察的变量放在另一个tab栏,如下效果:
![795730-20180106200536299-877995068.png](https://i-blog.csdnimg.cn/blog_migrate/288c090a24438c102a714f5d93f92cb6.png)
3、如果我们仅仅想观察指定几个变量的值的变化,可以点击Watches,点击+号,然后输入变量的名称回车就OK了。
如果变量名比较长我们可以选择Variables中的变量名然后右键,选择[Add to Watches],然后Watches面板中就有了
我们可以通过快速设置变量的值来加快调试速度,选择[Variables]中的变量名右键,选择[Set Value..]。
比如,我们在一次100次的for循环中,想观察第90次循环后的执行情况,就可以将循环次数手动改为90,这样就不用将循环控制变量从0点到90了。
附:测试代码
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
test();
Toast.makeText(this, "执行完毕", Toast.LENGTH_SHORT).show();
}
private void test() {
int value;
for (int i = 0; i < 10; i++) {
value = new Random().nextInt(100);
Log.i("bqt", "第" + i + "个随机数的值:" + value);
stepNext(i);
}
}
private void stepNext(int i) {
Toast.makeText(this, "i = " + i, Toast.LENGTH_SHORT).show();
}
}
23
23
1
public class MainActivity extends AppCompatActivity {
2
3
4
protected void onCreate(Bundle savedInstanceState) {
5
super.onCreate(savedInstanceState);
6
setContentView(R.layout.activity_main);
7
test();
8
Toast.makeText(this, "执行完毕", Toast.LENGTH_SHORT).show();
9
}
10
11
private void test() {
12
int value;
13
for (int i = 0; i < 10; i++) {
14
value = new Random().nextInt(100);
15
Log.i("bqt", "第" + i + "个随机数的值:" + value);
16
stepNext(i);
17
}
18
}
19
20
private void stepNext(int i) {
21
Toast.makeText(this, "i = " + i, Toast.LENGTH_SHORT).show();
22
}
23
}
2018-1-6