1. 程式人生 > >你所不知道的 Android Studio 除錯技巧

你所不知道的 Android Studio 除錯技巧

Android Studio目前已經成為開發Android的主要工具,用熟了可謂相當順手。作為開發者,除錯並發現bug,進而解決,可是我們的看家本領。正所謂,工欲善其事必先利其器,和其他開發工具一樣,如Eclipse、Idea,Android Studio也為我們提供了強大的除錯技巧,今天我們就來看看Android Studio中有關除錯的技巧。

首先,來看看Android studio中為我們提供的除錯面板(標準情況下):

142377-871fa25c68e74d9f

點選右上角Restore ‘Threads’View可先展示目前相關的執行緒資訊:

142377-fb6362fd716644a5

android studio大體為我們提供了7個功能區:

  1. 單步除錯區
  2. 斷點管理區
  3. 求值表示式
  4. 執行緒幀棧區
  5. 物件變數區
  6. 變數觀察區

下面我們分別對這七個區域進行介紹。

單步除錯區

該區提供了除錯的主要操作,和你所熟知的一樣的,主要有:Step over、step into、force step into、step out、drop frame。

Show Execution Point

142377-e2457e3b8ff168d6
點選該按鈕,游標將定位到當前正在除錯的位置.

Step Over

142377-a38e5abf8f423711

單步跳過,點選該按鈕將導致程式向下執行一行。如果當前行是一個方法呼叫,此行呼叫的方法被執行完畢後再到下一行。比如當前程式碼是: Java
123 intnum=10;intmin=Math.min(num,100);System.out.println(min);

如果當前除錯的是第二行,當點選step over時,Math.min(num,100)方法先執行完後跳到第三行.

Step Into

142377-8d6704f2dadaba55

單步跳入,執行該操作將導致程式向下執行一行。如果該行有自定義的方法,則進入該方法內部繼續執行,需要注意如果是類庫中的方法,則不會進入方法內部。

Force Step Into

142377-4f542a50ea15a7ea

強制單步跳入,和step into功能類似,主要區別在於:如果當前行有任何方法,則不管該方法是我們自行定義還是類庫提供的,都能跳入到方法內部繼續執行

Drop Frame

142377-3f00783c9feee676

沒有好記的名字,大意理解為中斷執行,並返回到方法執行的初始點,在這個過程中該方法對應的棧幀會從棧中移除.換言之,如果該方法是被呼叫的,則返回到當前方法被呼叫處,並且所有上下文變數的值也恢復到該方法未執行時的狀態。簡單的舉例來說明:

Java
12345678910111213141516 publicclassDebugDemo{privateStringname="default";publicvoidalertName(){System.out.println(name);debug();}publicvoiddebug(){this.name="debug";}publicstaticvoidmain(String[]args){newDebugDemo().alertName();}}

當你在除錯debug()時,執行該操作,將回調到debug()被呼叫的地方,也就是alertName()方法。如果此時再繼續執行drop frame,將回調到alertName()被呼叫的地方,也就是main().

Force Run to Cursor

142377-f5300d5e462a552c

非常好用的一個功能,可以忽視已經存在的斷點,跳轉到游標所在處.舉個簡單例子說明下:

142377-6d3b3b2872736b6f

比如現在第10行,此時我想除錯18行而又不想一步一步除錯,能不能一次到位呢?我們只需要將游標定位到相應的位置,然後執行Force Run to Cursor即可:

142377-fcf1af481bf6ae59

Evaluate expression

142377-f472de49ae7b6889

點選該按鈕會在當前除錯的語句處嵌入一個互動式直譯器,在該直譯器中,你可以執行任何你想要執行的表示式進行求值操作。比如,我們在除錯時執行到以下程式碼:

142377-d0f43a19e99660d7

此時執行Evaluate Expression,就相當於在除錯行之前嵌入了一個互動式直譯器,那麼在該直譯器中我們能做什麼呢?在這裡,我們可以對result進行求值操作:對著你想要求值得位置點選滑鼠右鍵,選擇evaluate Expression.此時會顯示如下:

142377-6b6e403beedab638

在彈出的輸入框中輸入求值表示式,比如這裡我們輸入Math.min(result,50),如下圖

142377-95f6f913b65626ef

點選執行,我們發現在Result中已經輸出了結果,如下:

142377-bc26935778ad51d0

斷點管理區

Return

142377-e07498375daeab8b

點選該按鈕會停止目前的應用,並且重新啟動.換言之,就是你想要重新除錯時,可以使用該操作,嗯,就是重新來過的意思.

Pause Program

142377-220f5c791c92785d

點選該按鈕將暫停應用的執行.如果想要恢復則可以使用下面提到的Resume Program.

Resume Program

142377-08ae28e77efebb24

該操作有恢復應用的含義,但是卻有兩種行為:

  1. 在應用處在暫停狀態下,點選該按鈕將恢復應用執行.
  2. 在很多情況下,我們會設定多個斷點以便除錯。在某些情況下,我們需要從當前斷點移動到下一個斷點處,兩個斷點之間的程式碼自動被執行,這樣我們就不需要一步一步除錯到下一個斷點了,省時又省力。舉例說明:
Java
123456 publicvoidtest(){test1();...test2();}

假設我們分別在第2行和第4行添加了斷點。如果此時我們除錯在第2行,此時點選執行該操作,當前除錯位置會自動執行到第4行,也就是第2到第4行之間的程式碼會自動被執行。

Stop

142377-01909a90658f1d10

點選該按鈕會通過相關的關閉指令碼來終止當前程序.換言之,對不同型別的工程可能有不同的停止行為,比如:對普通的Java專案,點選該按鈕意味著退出除錯模式,但是應用還會執行完成.而在Android專案中,點選該按鈕,則意味這app結束執行.

這裡我們以一個普通的JAVA工程為例:

142377-0dab1abaf08edf47 - 副本

此時如果我們執行停止操作,發現程式退出除錯模式,並正常執行完畢,Console中結果如下:

142377-9f9275ca54358664 - 副本

 View Breakpoints

142377-a11c97e61a615c4e

點選該按鈕會進入斷點管理介面,在這裡你可以檢視所有斷點,管理或者配置斷點的行為,如:刪除,修改屬性資訊等:

 142377-9ad9a6febe248fe4

Mute Breakpoints

142377-3cebad56c2774430

使用該按鈕來切換斷點的狀態:啟動或者禁用.在除錯過程中,你可以禁用暫時禁用所有的斷點,已實現應用正常的執行.該功能非常有用,比如當你在除錯過程中,突然不想讓斷點干擾你所關心的流程時,可以臨時禁用斷點.

Get thread dump

142377-280610b43f217a0c

獲取執行緒Dump,點選該按鈕將進入執行緒Dump介面:

142377-4b5e8d24b34b026d

藉此我們順便介紹一下dump介面:
執行緒工具區中最常用的是

142377-139652470b3ee48d

,可以用來過濾執行緒,其他的不做解釋了

解析來我們來認識一下執行緒的型別,表示為不同的圖示:

執行緒狀態描述 圖示
Thread is suspended.

這裡寫圖片描述
Thread is waiting on a monitor lock.

這裡寫圖片描述
Thread is running.

這裡寫圖片描述
Thread is executing network operation, and is waiting for data to be passed.

這裡寫圖片描述
Thread is idle.

這裡寫圖片描述
Event Dispatch Thread that is busy.

這裡寫圖片描述
Thread is executing disk operation.

這裡寫圖片描述

Settings

142377-ccd4db5d06e8af2f

點選該按鈕將開啟有關設定的列表: 142377-ab56ae7016596d20

我們對其中的幾個進行說明:

Show Values Inline

除錯過程中開啟該功能,將會程式碼右邊顯示變數值,即下圖中紅框所示部分:

142377-7a9bc7a021c7d748 - 副本

Show Method Return Values

除錯過程中啟用該功能,將在變數區顯示最後執行方法的返回值.舉個例子來說,首先,關閉該功能,我們除錯這段程式碼並觀察其變數區:

 142377-72ef59f2afd3ab7a開啟該功能之後,再來觀察變數區的變化:

 142377-d6ef8b9891f7dcd6

繼續往下除錯:

 142377-ffaf3666dace9698

繼續往下除錯:

 142377-ffaf3666dace9698這個功能簡直是棒極了,在除錯一段程式碼,並想看該程式碼中最後呼叫方法的最終結果時就非常有用了.

Auto-Variables Mode

開啟這個功能後,idea的Debugger會自動評估某些變數,大概就是當你執行在某個斷點時,Debugger會檢測當前除錯點之前或者之後的變數的狀態,然後在變數區選擇性輸出.舉個例子來說明,未開啟該功能之前,變數區輸出所有的變數資訊:

142377-336af7c2a3344b9a

開啟之後,當你除錯到第13行時,Debugger檢測到num變數在之後沒有被使用,那麼在變數區就不會輸出該變數的資訊.

142377-5a8f3a4165c4b8ea

Sort values alphabetically

開啟這個功能的化,變數區中的輸出內容會按照按字母順序進行排序,很簡單,不常用,還是按照預設的順序好.

Help

142377-50322e57a16e2d2f

這個不用說了,有任何不明白的都可以檢視官方幫助文件,這是我見到最好的文件之一.
其他幾個操作:Settings,Pin,Close留給各位自己去使用.

修改變數值

在除錯過程中,我們可以方便的修改某個變數的值,如下:

 142377-295088374ecd7ef8

在上圖中,當前result的值經過計算為10,這裡我們通過Set Value將其計算結果修改為100.

變數觀察區

該區域將顯示你所感興趣的變數的值。在除錯模式下,你可以通過Add to Watches將某個變數新增到觀察區,該值的變化將會在變數觀察區顯示。操作如下:

142377-26c51beb2674e6ad

這裡我們對name比較感興趣,希望看到它的值的變化情況,因此我們將其“特殊關照”。需要注意,此時因為name是成員變數,因此在物件觀察區也可看到該值。如果是區域性變數,無疑只能用這種方式了。

斷點的分類

到目前為止,我們已經簡單的介紹了除錯功能區,斷點管理區,求值表示式,這三個區域的功能。在上面,我們不斷的提到了斷點一次,但是斷點是什麼呢?想必大部分人已經知道了,我們這裡在簡單的說明下:

斷點是偵錯程式的功能之一,可以讓程式暫停在需要的地方,幫助我們進行分析程式的執行過程。

在Android Studio中,斷點又被以下五類:

  1. 條件斷點
  2. 日誌斷點
  3. 異常斷點
  4. 方法斷點
  5. 屬性斷點

其中方法斷點是我們最熟悉的斷點型別,相信沒有人不會。下面我們著重介紹其他四種類型的斷點。

條件斷點

所謂的條件斷點就是在特定條件發生的斷點,也就是,我們可將某個斷點設定為只對某種事件感興趣,最典型的應用就是在列表迴圈中,我們希望在某特定的元素出現時暫停程式執行。比如,現在我們有個list中,其中包含了q,1q,2q,3q四個元素,我們希望在遍歷到2q時暫停程式執行,那麼需要進行如下操作:
在需要的地方新增斷點,如下:

142377-35ab1f82dd3d629c

斷點處左鍵單擊,在Condition處填寫過濾條件.此處我們只關心2q,因此填寫s.equals("2q") 142377-03f5b57dfee7e3dd

日誌斷點

該型別的斷點不會使程式停下來,而是在輸出我們要它輸出的日誌資訊,然後繼續執行。具體操作如下:
同樣在斷點處左鍵單擊,在彈出的對話方塊中取消選中Suspend。

142377-687e79cc1093328f

在彈出的控制面板中,選中Log evaluated expression,然後再填寫想要輸出的日誌資訊,如下:

142377-b32cea0f283171fe

當除錯過程遇到該斷點將會輸出結果,如下:

142377-dbaff4b197befcb2

異常斷點

所謂的異常斷點就是在除錯過程中,一旦發生異常(可以指定某類異常),則會立刻定位到異常丟擲的地方。比如在除錯異常中,我們非常關注執行時異常,希望在產生任何執行異常時及時定位,那麼此時就可以利用該型別異常,在上線之前,進行異常斷點除錯非常有利於減少正式環境中發生crash的機率。

具體操作如下:在Run選單項中,選擇View Breakpoints(也可以在斷點管理面板中點選

142377-a11c97e61a615c4e
),如下:

142377-87f1928cadc086fb

在管理斷點面板中,點選+

142377-70e3887a0b657968

在彈出的下拉選擇列表中,我們選擇Java Exception Breakpoints

142377-a61ae7f8b012df11

這裡我們選中Search By Name,在下面的輸入框中輸入我們所關心的異常型別。此處我們關心NullPointerException,在除錯過程一旦發生NullPointerException,偵錯程式就會定位到異常發生處。

142377-572be4d83e4bdcc7

方法斷點

142377-fa592f990f69d0e5

(略過吧,應該沒人不知道了)

Filed WatchPoint

142377-031f2e553cc95299

Filed WatchPoint是本質上是一種特殊的斷點,也稱為屬性斷點:當我們某個欄位值被修改的時候,程式暫停在修改處。通常在除錯多執行緒時尤為可用,能幫我們及時的定位併發錯誤的問題。其使用和新增普通的斷點並無不同,斷點圖示稍有不同

除錯的兩種方式

到目前,除錯的相關基礎我們已經介紹完了,但是不少童鞋對Android Studio中

142377-09a477ed8cd9a4cb

這兩個按鈕感到困惑:Debug和Attach process。
這裡我們就簡單介紹一下這兩者的區別:

  • Debug:以除錯模式安裝執行,斷點可以在執行之前設定,也可在執行後設置,是多數人最常用的調式方式
  • Attach process:和Debug方式相比,能夠將偵錯程式attach到任何正在執行的程序。比如,我們可以通過attach process到想要除錯的程序。然後,在需要的地方設定相關斷點即可。

在具體除錯過程,自行酌情選擇即可。後面,我會帶大家一步一步除錯Android的Framework相關的原始碼,參見:
自己動手編譯最新Android原始碼及SDK自己動手除錯Android原始碼