原文地址: github.com/zhuanghongj… android
写代码不可避免会出现BUG,出现时就须要DEBUG。
git
若是看日志分析不出问题所在,可能就须要打断点去调试。
本文经过总结Android Studio的一些调试技巧来增强咱们发现并解决BUG的能力,而不是仅仅停留在“断点单步执行”上。github
先来看一段代码:
上图中左侧是咱们打的断点,由于断点所在代码类型不同或断点设置不同,所呈现的图标也不同。
在断点位置右键可对该断点进行设置,以下图express
断点大体可分为如下几类:多线程
如何进入调试模式?
通常来讲,下好断点后咱们有两种方式调试一个 并发
其中第二种方式较为经常使用(由于不用从新进行编译),只要运行过程当中触发到断点就能够直接进入调试模式。app
介绍下上面各个调试相关按钮的功能:
假设你的断点设置在一个循环列表里面,但你只对这个列表的某一个元素感兴趣,但愿循环到该元素时才触发断点。设置条件断点也很简单,在断点上右键弹出并设置你的条件便可。
为该断点设置的条件(假设咱们预期 “i等于7时” 才触发断点):
不少时候,调试是为了打印日志来定位异常代码来缩小范围,而后再使用断点找到问题所在。因此,常常要作的事情就是添加日志代码,好比输出函数参数、返回值或其余一些有用信息。
若是是经过 添加代码 打印相关日志,就须要从新编译整个应用,少则几十秒多则几分钟。
若是是经过 日志断点 打印相关日志,就能够彻底避免编译这些毫无心义的等待。
Suspend
属性取消勾选(这样虽然还叫作“断点”,但程序并不会在该断点断下来)Log message to console
和 Evaluate and log
(这样就会根据你指定的表达式将信息打印到控制台)最后,经过 Debug App 或 Attack process 方式运行程序。在 Console 面板下,不只能够看到你打印的 断点日志,还能够看到 正常Log类打印出来的日志。以下图:
传统的调试方法是以“行”为单位的,即“单步调试”。
但不少时候咱们只关心某个函数的参数或返回值。
使用方法断点,咱们能够再函数级别进行调试。
设置方法断点有两种方式:
在有些状况下,咱们只对某些特定的异常感兴趣,并且但愿程序在发生该异常时就能断下来,就像保存现场同样。Android Studio已经赋予了咱们这个能力,即 异常断点。
具体设置方法:打开
上图中咱们设置了关心的异常 IndexOutOfBoundsException,下面咱们写一段测试代码:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String[] strs = new String[]{"0", "1"};
Log.w("BP", strs[2]); // Index out of bounds
}
}复制代码
上面这段测试代码,若是是直接编译运行的话会致使App闪退。而若是是经过调试模式运行的话则会触发 Java Exception Breakpoints,代码编辑器会直接显示触发断点的代码,并在 Debug 面板上显示相关信息,以下图:注:若是此时你触发的是一个NullPointerException,则不会触发异常断点(由于尚未添加到“感兴趣”列表中)
有同窗会想,若是我捕捉了异常还会触发异常断点吗?
答:即便进行了 try...catch... 捕捉异常,断点依然会在 catch 以前触发
还有同窗会想,若是我对全部的异常或未知的异常感兴趣呢?
答:目前我也没找到好解决办法,试了“勾选 Any Exception”、“添加 Exception”、“添加 UndeclaredThrowableException” 这几种方法,都未能快速定位到异常代码,知道的同窗能够PR下。
前面咱们添加“异常断点”而且点击“加号”后,显示的第二个项 Java Field Watchpoints 是干什么的呢?
有木有这样一种场景:某个变量的值莫名奇妙地不知道被谁修改了?
Java虽然是值传递,但引用也能够是值。全部的对象都存放在堆上面,而堆是被全部线程共享的。所以,在复杂状况下,你根本不知道这些共享变量是被谁修改了,也不知道具体的函数调用路径。哥,这很危险。
在多线程环境下,不变性是一个很重要的特性,高并发性语言(如 Erlang、Scala 等)都对这种不变性有着必定程度的支持。
废话了这么多,如今进入正题。
Field WatchPoint 就是咱们解决上面难题的关键所在,使用它使得咱们能够在某个 Field
被访问或者被修改的时候触发断点,设置方法有两种:
下面用一段代码来实践下:
public class MainActivity extends AppCompatActivity {
private String mField;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mField = "ABC"; // 1. 修改值
changeFieldMethod1();
}
private void changeFieldMethod1() {
changeFieldMethod2();
}
private void changeFieldMethod2() {
mField = "Android"; // 2. 修改值
Log.i("BP", "mField = " + mField); // 3. 访问值
}
}复制代码
咱们对 mField
设置了 Field WatchPoint 并同时勾选了 Field access 和 Field modification,所以在一、2和3的位置都会触发断点。当在位置2触发断点的时候,Debug面板的显示内容以下图:
在上图中咱们能够看到函数的具体调用路径,以及未执行触发断点代码前所观察变量的值。
Evaluate Expression 能够直接理解为“计算表达式的值”。
这也是一个很是实用的功能,能够在断点处直接进入一个求值环境(前面提到过该功能的按钮图标及含义),执行任何你感兴趣的表达式或代码片断:
上面介绍了“各类断点”、“变量观察”、“表达式求值”等功能及其相关演示,实际上调试相关知识远不止这么多。
好比,打开 View BreakPoint 设置窗口,以下图:
咱们能够对感兴趣的 特定对象、特定类 进行下断点,也能够设置 断点次数 或设置触发断点的 特定线程 等。
差多不先总结到这里,想到的话再补充。
参考文章: