為應用程式偵錯

Android Studio 提供偵錯工具,可讓您執行以下及其他操作:

  • 選取要在哪個裝置上對應用程式偵錯。
  • 設定 Java、Kotlin 和 C/C++ 程式碼的中斷點。
  • 在執行階段檢查變數及評估運算式。

本頁提供基本偵錯工具作業的操作說明。如需其他說明文件,另請參閱 IntelliJ IDEA 偵錯文件

啟用偵錯功能

開始偵錯前,請先完成下列步驟:

啟用裝置偵錯功能。
如果您使用的是模擬器,系統會預設啟用這項功能。但如果是連結的裝置,您必須在裝置開發人員選項中啟用偵錯功能
執行可進行偵錯的建構變化版本。

使用建構設定中包含 debuggable true (Kotlin 指令碼中的 isDebuggable = true) 建構變化版本

通常,您可以選取每個 Android Studio 專案包含的預設「debug」變化版本,即使未顯示在 build.gradle 檔案中仍可選取。但如果您定義了應可進行偵錯的新建構類型,則必須在建構類型中加入 debuggable true

Groovy

android {
    buildTypes {
        customDebugType {
            debuggable true
            ...
        }
    }
}

Kotlin

android {
    buildTypes {
        create("customDebugType") {
            isDebuggable = true
            ...
        }
    }
}

這個屬性也適用於含有 C/C++ 程式碼的模組

注意:系統不再使用 jniDebuggable 屬性。

如果您的應用程式依附於程式庫模組,而您也想對該模組偵錯,則必須將程式庫與 debuggable true 一併附在套件中,讓程式庫保留偵錯符號。如要確保應用程式專案的可偵錯變化版本接收程式庫模組的可偵錯變化版本,請發布程式庫的非預設版本。

開始偵錯

您可以按照以下方式開始偵錯工作階段:

  1. 在應用程式的程式碼中設定中斷點
  2. 在工具列的目標裝置選單中,選取要在哪個裝置上對應用程式偵錯。
    目標裝置選單。
    圖 1. 目標裝置選單。

    如果您尚未設定任何裝置,則必須透過 USB 連接裝置透過 Wi-Fi 建立裝置連線,或是建立 AVD,才能使用 Android Emulator

  3. 按一下工具列中的「Debug」圖示

    如果您的應用程式已在裝置上執行,系統會顯示對話方塊,詢問是否要從「Run」切換至「Debug」。裝置必須重新啟動,才能開始偵錯。如要讓同一個應用程式執行個體保持運作,請按一下「Cancel Debug」,然後將偵錯工具附加至執行中的應用程式。否則,Android Studio 會建構 APK、使用偵錯金鑰進行簽署,然後在所選裝置上安裝並執行該 APK。

    如果您將 C 和 C++ 程式碼新增至專案,Android Studio 也會在「Debug」視窗中執行 LLDB 偵錯工具,對您的原生程式碼偵錯。

  4. 如果「Debug」視窗未開啟,請依序點選「View」>「Tool Windows」>「Debug」,或按一下工具視窗列中的「Debug」圖示

將偵錯工具附加至執行中的應用程式

如果應用程式已在裝置上執行,您不必重新啟動應用程式,就可以開始偵錯,方法如下:

  1. 按一下「Attach debugger to Android process」圖示
  2. 在「Choose Process」對話方塊中,選取要附加偵錯工具的程序。
    1. 如果使用的是模擬器或已解鎖裝置,勾選「Show all processes」即可查看所有程序。在已解鎖裝置上,系統會顯示裝置上執行的所有程序。但在未解鎖裝置上,系統只會顯示可進行偵錯的程序。
    2. 從「Use Android Debugger Settings from」選單中,選取現有的執行/偵錯設定。對於 C 和 C++ 程式碼,這麼做可讓您在現有設定中重複使用 LLDB 啟動指令、LLDB 附加後指令和符號目錄。
    3. 如果目前沒有執行/偵錯設定,請選取「Create New」。這個選項會啟用「Debug Type」選單,您可以在這裡選取不同的偵錯類型。根據預設,Android Studio 會使用「Detect Automatically」偵錯類型,根據專案是否包含 Java 或 C/C++ 程式碼,選擇最適合的偵錯工具選項。
  3. 按一下「OK」

    系統會隨即顯示「Debug」視窗。

Device Explorer (依序選取「View」>「Tool Windows」>「Device Explorer」) 中的「Processes」分頁也提供可進行偵錯程序的清單。在這個頁面中,您可以選取特定程序並執行終止 、強制停止 ,或將偵錯工具附加到指定程序

偵錯視窗

圖 2.「Debug」視窗。

偵錯視窗劃分為以下各部分:

  1. 執行和導覽工具列:請參閱「使用中斷點」ㄧ節。
  2. 執行緒選取器
  3. 評估和觀察運算式項目:請參閱「檢查變數」一節。
  4. 堆疊顯示
  5. 變數窗格:請參閱「檢查變數」一節。

注意:Android Studio 偵錯工具和垃圾收集器已大致整合。Android 虛擬機器會保證在偵錯工具中斷連線之前,系統都不會將偵錯工具發現的任何物件收集為垃圾。在偵錯工具連線的情況下,這可能會導致系統在一段時間後積聚物件。舉例來說,如果偵錯工具看到執行中的執行緒,則直到偵錯工具中斷連線前,系統都不會將相關的 Thread 物件收集為垃圾,即使執行緒已終止也一樣。

變更偵錯工具類型

由於必須使用不同偵錯工具對 Java/Kotlin 程式碼和 C/C++ 程式碼偵錯,Android Studio 偵錯工具會讓您選取要使用的偵錯工具類型。根據預設,Android Studio 會使用「Detect Automatically」偵錯工具類型,根據在專案中偵測到的語言,決定要使用的偵錯工具。

如要在偵錯設定中手動選取偵錯工具,請依序點選「Run」>「Edit Configurations」。您也可以依序點選「Run」>「Attach debugger to Android process」,在隨即顯示的對話方塊中選取偵錯工具。

可用的偵錯類型如下:

Detect Automatically
如果想讓 Android Studio 自動針對要偵錯的程式碼選擇最佳選項,請選取這個偵錯類型。舉例來說,如果專案中有 C 或 C++ 程式碼,Android Studio 會自動使用「Dual」偵錯類型。否則,Android Studio 會使用「Java-Only」偵錯類型。
Java Only
如果只想針對以 Java 或 Kotlin 編寫的程式碼偵錯,請選取這個偵錯類型。Java-Only 偵錯工具會忽略您在原生程式碼設定的中斷點或觀察點。
Native Only (僅適用於 C/C++ 程式碼)
如果只想使用 LLDB 對程式碼偵錯,請選取這個偵錯類型。採用該偵錯類型時,無法查看 Java 偵錯工具的工作階段檢視畫面。根據預設,LLDB 只會檢查原生程式碼,並忽略 Java 程式碼內的中斷點。如要一併對 Java 程式碼偵錯,請改用「Detect Automatically」或「Dual」偵錯類型。

Native 偵錯功能僅適用於符合下列條件的裝置:

  • 裝置支援 run-as

    如要確認裝置是否支援 run-as,請在已連線至裝置的 ADB 殼層中執行下列指令:

    run-as your-package-name pwd
    

    your-package-name 替換成應用程式的套件名稱。如果裝置支援 run-as,則指令傳回時不應出現任何錯誤。

  • 裝置已啟用 ptrace

    如要檢查 ptrace 是否已啟用,請在已連線至裝置的 ADB 殼層中執行下列指令:

    sysctl kernel.yama.ptrace_scope
    

    如果已啟用 ptrace,這個指令會輸出值 0unknown key 錯誤。如果未啟用 ptrace,則會輸出 0 以外的值。

Dual (Java + Native) - 僅適用於 C/C++ 程式碼
如果偵錯時要在 Java 和原生程式碼之間切換,請選取這個偵錯類型。Android Studio 會同時將 Java 偵錯工具和 LLDB 附加至應用程式程序,方便您檢查 Java 和原生程式碼內的中斷點,不必重新啟動應用程式或變更偵錯設定。

請注意圖 2 中「Debug」視窗名稱右側的兩個分頁。由於應用程式同時含有 Java 和 C++ 程式碼,其中一個分頁用於原生程式碼偵錯,另一個分頁則用於 Java 程式碼偵錯,如「-java」所示。

圖 3. 用於原生程式碼偵錯的分頁,以及用於 Java 程式碼偵錯的分頁。

注意:若原生程式碼經過編譯器最佳化調整,您在予以偵錯時,可能會收到以下警告訊息:
This function was compiled with optimizations enabled. Some debugger features may not be available。使用最佳化標記時,編譯器會變更編譯的程式碼,藉此提高執行效率。偵錯工具可能因此難以將最佳化的編譯程式碼對應至原本的原始碼,導致回報非預期或不正確的資訊。因此,建議您在對原生程式碼偵錯時停用編譯器最佳化功能。

使用系統記錄

系統記錄會在應用程式偵錯時顯示系統訊息。這些訊息包括裝置上執行的應用程式資訊。如要使用系統記錄對應用程式偵錯,請確認應用程式在開發階段時,程式碼可以寫入記錄訊息,並輸出例外狀況堆疊追蹤。

編寫程式碼中的記錄訊息

如要在程式碼中編寫記錄訊息,請使用 Log 類別。記錄訊息可在您與應用程式互動時收集系統偵錯輸出內容,協助您瞭解執行流程。此外,記錄訊息也可以指出應用程式出錯的部分。如要進一步瞭解記錄功能,請參閱「使用 Logcat 查看記錄」。

以下範例說明如何新增記錄訊息,協助您在活動開始時,判斷先前的狀態資訊是否可供使用:

Kotlin

import android.util.Log
...
class MyActivity : Activity() {
    ...
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        if (savedInstanceState != null) {
            Log.d(TAG, "onCreate() Restoring previous state")
            /* restore state */
        } else {
            Log.d(TAG, "onCreate() No saved state available")
            /* initialize app */
        }
        ...
    }
  ...
  companion object {
    private val TAG: String = MyActivity::class.java.simpleName
    ...
  }
}

Java

import android.util.Log;
...
public class MyActivity extends Activity {
    private static final String TAG = MyActivity.class.getSimpleName();
    ...
    @Override
    public void onCreate(Bundle savedInstanceState) {
       ...
       if (savedInstanceState != null) {
            Log.d(TAG, "onCreate() Restoring previous state");
            /* restore state */
        } else {
            Log.d(TAG, "onCreate() No saved state available");
            /* initialize app */
        }
        ...
    }
}

在開發期間,您的程式碼也可以擷取例外狀況,並將堆疊追蹤寫入系統記錄:

Kotlin

fun someOtherMethod() {
    try {
        ...
    } catch (e : SomeException) {
        Log.d(TAG, "someOtherMethod()", e)
    }
}

Java

void someOtherMethod() {
    try {
        ...
    } catch (SomeException e) {
        Log.d(TAG, "someOtherMethod()", e);
    }
}

注意:準備好發布應用程式時,請從程式碼中移除偵錯記錄訊息和堆疊追蹤輸出呼叫。做法是設定 DEBUG 標記,並將偵錯記錄訊息放入條件陳述式。

查看系統記錄

您可以在 Logcat 視窗中查看及篩選偵錯和其他系統訊息,如圖 4 所示。舉例來說,您可以查看垃圾收集發生時的訊息,或查看那些使用 Log 類別新增至應用程式中的訊息。

如要使用 Logcat,請開始偵錯,並選取「Logcat」分頁標籤。

圖 4. 包含篩選器設定的「Logcat」視窗。

如需 Logcat 和篩選選項的說明,請參閱「使用 Logcat 查看記錄」。

使用中斷點

Android Studio 支援會觸發不同偵錯動作的中斷點。中斷點分為幾種類型:

行中斷點
最常見的類型是行中斷點,用於在指定的程式碼行暫停執行應用程式。在暫停期間,您可以檢查變數、評估運算式,然後逐行執行,判斷執行階段錯誤的原因。
方法中斷點
方法中斷點指的是應用程式進入或結束特定方法時,會暫停執行應用程式。在暫停期間,您可以檢查變數、評估運算式,然後逐行執行,判斷執行階段錯誤的原因。在可組合函式上設定中斷點時,偵錯工具會列出可組合項的參數及其狀態,協助找出可能導致重組的變更。
欄位中斷點
欄位中斷點指的是應用程式讀取或寫入特定欄位時,會暫停執行應用程式。
例外狀況中斷點
擲回例外狀況時,例外狀況中斷點會暫停執行應用程式。

您可以設定條件式中斷點,只在符合特定條件時暫停執行作業。您也可以設定記錄中斷點,不必暫停執行作業就能寫入 Logcat。這有助於避免在程式碼中胡亂放入記錄陳述式。

如要新增行中斷點,請按照下列步驟操作:

  1. 找出要暫停執行作業的程式碼行。
  2. 按一下程式碼行中的左側空白邊,或是在該行放入插入點,然後按下 Control+F8 鍵 (在 macOS 上則是 Command + F8 鍵)。
  3. 如果應用程式已在執行,請按一下「Attach debugger to Android process」圖示 。否則,請按一下「Debug」圖示 開始偵錯。

設定中斷點時,程式碼行旁邊會顯示紅點,如圖 5 所示。

圖 5. 設定中斷點時,程式碼行旁邊會顯示紅點。

當程式碼執行到中斷點時,Android Studio 就會暫停執行應用程式。

如要確認應用程式的狀態,請使用「Debugger」分頁中的工具:

  • 如要檢查變化版本的物件樹狀結構,請在「Variables」檢視畫面中展開該結構。如果找不到「Variables」檢視畫面,請按一下「Layout Settings」圖示 ,確認已勾選「variables」

  • 如要前往下一行程式碼 (不進入方法),請按一下「Step Over」圖示

  • 如要前往方法呼叫中的第一行,請按一下「Step Into」圖示

  • 如要前往目前方法外的下一行,請按一下「Step Out」圖示

  • 如要繼續照常執行應用程式,請按一下「Resume Program」圖示

如果專案會使用原生程式碼,根據預設,「Detect Automatically」偵錯類型會同時將 Java 偵錯工具和 LLDB 附加至應用程式,以兩個不同的程序執行。因此,您不必重新啟動應用程式或變更設定,就能在 Java 和 C/C++ 的檢查中斷點間切換。

注意:如要讓 Android Studio 偵測 C 或 C++ 程式碼的中斷點,必須使用支援 LLDB 的偵錯類型,例如 Detect Automatically、Native 或 Dual。如要變更 Android Studio 使用的偵錯類型,請編輯偵錯設定。如要進一步瞭解不同的偵錯類型,請參閱有關使用其他偵錯類型的章節。

當 Android Studio 將應用程式部署至目標裝置時,「Debug」視窗會隨即開啟,其中針對每個偵錯工具程序開啟分頁或偵錯工作階段檢視畫面,如圖 6 所示。

圖 6. 使用 LLDB 對原生程式碼偵錯。
  1. 當 LLDB 偵錯工具遇到 C/C++ 程式碼內的中斷點,Android Studio 就會切換至「<your-module>分頁。「Frames」、「Variables」和「Watches」窗格也可供使用,而且運作方式與進行 Java 程式碼偵錯時相同。

    雖然 LLDB 工作階段檢視畫面中並未提供「Threads」窗格,但您可以使用「Frames」窗格中的清單存取應用程式程序。如要進一步瞭解這些窗格,請參閱「偵錯視窗框架」和「檢查變數」等章節。

    注意:檢查原生程式碼內的中斷點時,Android 系統會將執行應用程式 Java 位元碼的虛擬機器暫停。這表示檢查原生程式碼內的中斷點時,您將無法與 Java 偵錯工具互動,也無法從 Java 偵錯工具工作階段擷取狀態資訊。

  2. 當 Java 偵錯工具遇到 Java 或 Kotlin 程式碼內的中斷點時,Android Studio 就會切換至「<your-module>-java」分頁。
  3. 使用 LLDB 偵錯時,您可以使用 LLDB 工作階段檢視畫面中的 LLDB 終端機,將指令列選項傳遞給 LLDB。如果您希望 LLDB 在每次應用程式偵錯作業開始時執行特定指令,無論是在偵錯工具附加至應用程式程序之前或之後立即執行,都可以將這些指令新增至偵錯設定

對 C/C++ 程式碼偵錯時,您還可以設定特殊類型的中斷點 (稱為「觀察點」),用於在應用程式與特定記憶體區塊互動時,暫停應用程式程序。詳情請參閱關於如何新增觀察點的章節。

查看及設定中斷點

如要查看所有中斷點並調整中斷點設定,請按一下「Debug」視窗中的「View Breakpoints」圖示 。「Breakpoints」視窗會隨即顯示,如圖 7 所示。

圖 7. 「Breakpoints」視窗會列出目前所有中斷點,並顯示各中斷點的行為設定。

「Breakpoints」視窗可讓您從窗格清單中啟用或停用各個中斷點。如果中斷點已停用,Android Studio 不會在執行到中斷點時暫停應用程式。

從清單中選取中斷點即可調整設定。您可以先將中斷點設為停用,然後讓系統在執行到其他中斷點後再啟用。您也可以設定執行到中斷點後是否應停用該中斷點。如要為例外狀況設定中斷點,請在中斷點清單中選取「Exception Breakpoints」

如要暫時停用所有中斷點,請按一下「Debug」視窗中的「Mute Breakpoints」圖示 。再按一下即可重新啟用。

偵錯視窗框架

在「Debugger」視窗中,「Frames」窗格可讓您檢查導致執行到目前中斷點的堆疊框架。您可以藉此瀏覽及檢查堆疊框架,並檢查 Android 應用程式中的執行緒清單。

如要選取執行緒,請使用執行緒選取器選單,並查看執行緒的堆疊框架。按一下框架中的元素,即可在編輯器中開啟來源。您也可以自訂執行緒顯示方式,並按照檢查框架指南中的說明匯出堆疊框架。

檢查變數

在「Debugger」視窗中,「Variables」窗格可讓您在系統於中斷點停止應用程式時檢查變數,然後從「Frames」窗格選取框架。您還可透過「Variables」窗格使用靜態方法和/或所選框架內提供的變數,評估特設運算式。

如何在對應用程式偵錯時,將運算式加入物件樹狀結構:

圖 8. 「Debug」視窗中的物件樹狀結構和運算式項目方塊。
  1. 輸入運算式即可進行觀察或顯示。
  2. 按一下「Add to watches」或按下 Enter 鍵即可評估運算式一次。

或者,如果物件樹狀結構包含要觀察的運算式,可以將其拖曳至樹狀結構頂端,新增為已觀察的運算式。

應用程式執行到中斷點或逐步執行程式碼時,會更新已觀察的運算式。

除非您手動評估其他運算式或逐步執行程式碼,否則評估過的運算式仍會顯示在物件樹狀結構頂端。

如要從物件樹狀結構中移除已觀察的運算式,請在運算式上按一下滑鼠右鍵,然後點選「Remove Watch」

新增觀察點

對 C/C++ 程式碼偵錯時,您可以設定特殊類型的中斷點 (稱為「觀察點」),以便在應用程式與特定記憶體區塊互動時,暫停應用程式程序。舉例來說,假設您將兩個指標設為指向某個記憶體區塊,並針對該區塊指派觀察點,則使用任一指標存取該記憶體區塊均會觸發觀察點。

在 Android Studio 中,只要選取特定變數,就能在執行階段建立觀察點,但 LLDB 只會將觀察點指派至系統分配給該變數的記憶體區塊,而非變數本身。這與在「Watches」窗格中新增變數的做法不同。「Watches」可讓您觀察變數的值,但系統在記憶體中讀取或變更該變數的值時,您無法暫停應用程式程序。

注意:當應用程式程序結束函式時,系統會從記憶體解除該函式區域變數的分配狀態,因此您必須重新指派為這些變數建立的觀察點。

您必須符合下列條件,才能設定觀察點:

  • 目標實體裝置或模擬器使用 x86 或 x86_64 CPU。如果裝置使用 ARM CPU,則必須將記憶體中變數位址的界線對齊至適合 32 位元處理器的 4 個位元組,或 64 位元處理器的 8 個位元組。如要對齊原生程式碼中的變數,請在變數宣告中指定 __attribute__((aligned(num_bytes))),如下所示:
    // For a 64-bit ARM processor
    int my_counter __attribute__((aligned(8)));
  • 您指派的觀察點不超過三個。Android Studio 在 x86 或 x86_64 目標裝置上最多只能支援四個觀察點。其他裝置可能支援較少觀察點。

注意:使用 32 位元 ARM ABI 對應用程式偵錯時,如果新增觀察點或將滑鼠遊標懸停在程式碼內的變數上來檢查數值,可能會造成當機情形。請改用 64 位元的 ARM、x86 或 x86_64 二進位檔偵錯。日後推出的 Android Studio 版本將會修正這個問題。

如果您符合上述條件,可以按照下列步驟新增觀察點:

  1. 應用程式在中斷點暫停時,請前往 LLDB 工作階段檢視畫面中的「Variables」窗格。
  2. 在要追蹤的記憶體區塊中,對其中的變數按一下滑鼠右鍵,然後選取「Add Watchpoint」

    圖 9. 將觀察點新增至記憶體中的變數。
  3. 用於設定觀察點的對話方塊會隨即顯示,如圖 9 所示。

    透過下列選項設定觀察點:

    • 「Enabled」:如要讓 Android Studio 在設定變更前忽略觀察點,請取消選取這個選項。Android Studio 會儲存觀察點,方便您日後存取。
    • 「Suspend」:根據預設,Android 系統存取已指派給觀察點的記憶體區塊時,會暫停應用程式程序。如果不要採用這項行為,請取消選取這個選項。接著畫面上會顯示其他選項,例如「Log message to console」和「Remove when hit」,讓您用於自訂系統與觀察點互動時的行為。
    • 「Access Type」:選取應用程式在嘗試「Read」或「Write」系統分配給該變數的記憶體區塊時,是否觸發觀察點。如要在讀取或寫入時觸發觀察點,請選取「Any」
  4. 按一下「Done」

如要查看所有觀察點並調整觀察點設定,請按一下「Debug」視窗中的「View Breakpoints」圖示 。「Breakpoints」對話方塊會隨即顯示,如圖 10 所示。

圖 10. 「Breakpoints」對話方塊會列出目前的觀察點,並顯示各觀察點的行為設定。

新增觀察點後,按一下「Debug」視窗中的「Resume Program」圖示 ,即可繼續執行應用程式程序。根據預設,如果應用程式嘗試存取設有觀察點的記憶體區塊,Android 系統會暫停應用程式程序,接著在應用程式上次執行的程式碼行旁邊,會顯示觀察點圖示 ,如圖 11 所示。

圖 11. Android Studio 會指出觸發觀察點前,應用程式正在執行的程式碼行。

查看及變更資源值顯示格式

在偵錯模式中,您可以查看資源值,並為 Java 或 Kotlin 程式碼中的變數選取不同的顯示格式。看到畫面上顯示「Variables」分頁並選取框架後,請執行下列步驟:

  1. 在「Variables」清單中對資源行中的任何位置按一下滑鼠右鍵,即可顯示清單。
  2. 在清單中選取「View as」,然後選取要使用的格式。

    可用的格式取決於所選資源的資料類型。您可能會看到下列一或多個選項:

    • 「Class」:顯示類別定義。
    • toString:顯示字串格式。
    • Object:顯示物件 (類別的例項) 定義。
    • Array:以陣列格式顯示。
    • 「Timestamp」:以下列格式顯示日期和時間:yyyy-mm-dd hh:mm:ss。
    • 「Auto」:Android Studio 會根據資料類型選擇最適合的格式。
    • 「Binary」:使用零和一顯示二進位值。
    • MeasureSpec:從父項傳遞至所選子項的值。 查看 MeasureSpec
    • 「Hex」:以十六進位值顯示。
    • 「Primitive」:以使用原始資料類型的數值顯示。
    • 「Integer」:顯示 Integer 類型的數值。

如要建立自訂格式,請執行下列步驟:

  1. 在資源值上按一下滑鼠右鍵。
  2. 選取「View as」
  3. 選取「建立」
  4. 系統會隨即顯示「Java Data Type Renderers」對話方塊。請按照「Java Data type renderers」中的說明操作。