原文地址: 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 設置窗口,以下圖:
咱們能夠對感興趣的 特定對象、特定類 進行下斷點,也能夠設置 斷點次數 或設置觸發斷點的 特定線程 等。
差多不先總結到這裏,想到的話再補充。
參考文章: