Android Studio 中的調試技巧


原文地址: github.com/zhuanghongj… android

寫代碼不可避免會出現BUG,出現時就須要DEBUG。
git

若是看日誌分析不出問題所在,可能就須要打斷點去調試。
本文經過總結Android Studio的一些調試技巧來增強咱們發現並解決BUG的能力,而不是僅僅停留在「斷點單步執行」上。github

1、概述

先來看一段代碼:

上圖中左側是咱們打的斷點,由於斷點所在代碼類型不同或斷點設置不同,所呈現的圖標也不同。
在斷點位置右鍵可對該斷點進行設置,以下圖express

  • 變量(相關設置窗口)
    編程

  • 方法(相關設置窗口)
    android-studio

  • 普通代碼(相關設置窗口)
    bash

斷點大體可分爲如下幾類:多線程

  • 普通斷點
  • 條件斷點
  • 日誌斷點
  • 方法斷點
  • 異常斷點

2、調試基礎

如何進入調試模式?


通常來講,下好斷點後咱們有兩種方式調試一個 併發

Debuggable
Apk

  • Debug App:從新編譯並安裝該應用(上圖左紅圈按鈕)
  • Attach Debugger to Android process:點擊後須要選擇對應的進程(上圖右紅圈按鈕)

其中第二種方式較爲經常使用(由於不用從新進行編譯),只要運行過程當中觸發到斷點就能夠直接進入調試模式。app

介紹下上面各個調試相關按鈕的功能:

圖標 名稱 功能描述
Resume Program 當你運行到某個斷點的時候,點擊以後會繼續程序的運行
(後面若是有斷點的話會暫停在該斷點出)
Pause Program 暫停運行
Stop App 中止程序
View Breakpoints 查看全部斷點
Mute Breakpoints 沉默全部斷點
(選中後全部斷點圖標的主色調都會編程灰白色,而且不會觸發任何斷點)
Get Thread Dump 顯示線程相關信息
Restore Layout TODO
Settings 設置
Show Excution Points TODO
Step Over 單步執行,能夠簡單理解爲「執行到下一行代碼」
Step Into 進入當前方法內部
Force Step Into TODO
Step Out 跳出當前方法
Drop Frame TODO
Run To Cursor 直接運行到「浮標」所在的那行代碼
Evaluate Expression 進行表達式求值

3、條件斷點

假設你的斷點設置在一個循環列表裏面,但你只對這個列表的某一個元素感興趣,但願循環到該元素時才觸發斷點。設置條件斷點也很簡單,在斷點上右鍵彈出並設置你的條件便可

先看一個打了條件斷點的代碼:

爲該斷點設置的條件(假設咱們預期 「i等於7時」 才觸發斷點):

觸發斷點後,查看Debugger面板:

  • 面板左側:顯示了方法調用棧及對應信息:方法名,行號,類名和包名
  • 面板右側:顯示了當前各個變量的值

4、日誌斷點

不少時候,調試是爲了打印日誌來定位異常代碼來縮小範圍,而後再使用斷點找到問題所在。因此,常常要作的事情就是添加日誌代碼,好比輸出函數參數、返回值或其餘一些有用信息。

若是是經過 添加代碼 打印相關日誌,就須要從新編譯整個應用,少則幾十秒多則幾分鐘。
若是是經過 日誌斷點 打印相關日誌,就能夠徹底避免編譯這些毫無心義的等待。

再來看一段代碼:

在想要打印日誌的地方下斷點,而後右鍵該斷點並進行相關設置:

  • Suspend 屬性取消勾選(這樣雖然還叫作「斷點」,但程序並不會在該斷點斷下來)
  • 而後勾選 Log message to consoleEvaluate and log(這樣就會根據你指定的表達式將信息打印到控制檯)

最後,經過 Debug AppAttack process 方式運行程序。在 Console 面板下,不只能夠看到你打印的 斷點日誌,還能夠看到 正常Log類打印出來的日誌。以下圖:

5、方法斷點

傳統的調試方法是以「行」爲單位的,即「單步調試」。
但不少時候咱們只關心某個函數的參數或返回值。
使用方法斷點,咱們能夠再函數級別進行調試。

設置方法斷點有兩種方式:

  • 在方法行打上斷點(注意看,左邊的圖標跟普通斷點的圖標是不同的噢)
  • 經過斷點設置窗口(View BreakPoints -> Add -> Java Method Breakpoints)

6、異常斷點

在有些狀況下,咱們只對某些特定的異常感興趣,並且但願程序在發生該異常時就能斷下來,就像保存現場同樣。Android Studio已經賦予了咱們這個能力,即 異常斷點

具體設置方法:打開

「View Breakpoints」
,點擊加號並添加你感興趣的異常

上圖中咱們設置了關心的異常 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下。

7、Field WatchPoint

前面咱們添加「異常斷點」而且點擊「加號」後,顯示的第二個項 Java Field Watchpoints 是幹什麼的呢?
有木有這樣一種場景:某個變量的值莫名奇妙地不知道被誰修改了?

Java雖然是值傳遞,但引用也能夠是值。全部的對象都存放在堆上面,而堆是被全部線程共享的。所以,在複雜狀況下,你根本不知道這些共享變量是被誰修改了,也不知道具體的函數調用路徑。哥,這很危險。

在多線程環境下,不變性是一個很重要的特性,高併發性語言(如 Erlang、Scala 等)都對這種不變性有着必定程度的支持。

廢話了這麼多,如今進入正題。
Field WatchPoint 就是咱們解決上面難題的關鍵所在,使用它使得咱們能夠在某個 Field 被訪問或者被修改的時候觸發斷點,設置方法有兩種:

  • 第一種:直接在某個變量的聲明處下斷點(此時斷點圖標和普通斷點圖標也是不同的)
    右鍵該斷點能夠進行設置

  • 第二種:在 View BreakPoints 中進行設置,直接指定某個類的某個變量

下面用一段代碼來實踐下:

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 accessField modification,所以在一、2和3的位置都會觸發斷點。當在位置2觸發斷點的時候,Debug面板的顯示內容以下圖:

在上圖中咱們能夠看到函數的具體調用路徑,以及未執行觸發斷點代碼前所觀察變量的值。

8、Evaluate Expression

Evaluate Expression 能夠直接理解爲「計算表達式的值」。
這也是一個很是實用的功能,能夠在斷點處直接進入一個求值環境(前面提到過該功能的按鈕圖標及含義),執行任何你感興趣的表達式或代碼片斷:

  • 表達式求值
  • 代碼片斷求值

9、小結

上面介紹了「各類斷點」、「變量觀察」、「表達式求值」等功能及其相關演示,實際上調試相關知識遠不止這麼多。
好比,打開 View BreakPoint 設置窗口,以下圖:
咱們能夠對感興趣的 特定對象特定類 進行下斷點,也能夠設置 斷點次數 或設置觸發斷點的 特定線程 等。

差多不先總結到這裏,想到的話再補充。

參考文章:

相關文章
相關標籤/搜索