本文通過Android Studio工具來講述你不曾知道的一些Debug小技巧。文中有許多操作,不需要死記硬背,隻需浏覽一遍,了解一番,增加個印象。等到要上手操作的時候,再憶起本文,回來檢視檢視。久而久之你就能熟能生巧,成為一代Debug大師!
Android Studio 版本
使用版本為3.5.3
調試項目
調試的項目隻有一張頁面,由 RecyclerView + 底部一個Button組成。

使用Logcat檢視日志技巧
去除多餘資訊
為了友善舉例,我使用
addOnScrollListener(...)
方法來監聽RecyclerView的滑動事件,然後在
onScrolled(...)
方法裡,通過
Log.d("recycler_view", "recycler view was Scrolled...")
把資訊列印到控制台,如下圖所示:
大家可能注意到,上圖中有許多内容是我們不需要關心的,例如紅圈裡面的時間、線程與包名。這時我們可以點選右邊工具欄的
Logcat Header
圖示,來把這些資訊移除,如:
我們隻保留一個TAG,這樣我們Logcat界面就會變得清爽很多,看下效果:
過濾結果
在Logcat界面的搜尋欄中,我們可以輸入自定義的TAG來過濾結果:
但如果存在多個TAG的時候,我們應該把它們儲存起來,這樣才不僅友善我們回過頭來繼續檢視,也無須在腦中開辟塊空間把TAG名記住。來來來,一起動手來編輯一下過濾器配置:
圖中左上角的“+”是添加,“-”是移除。
添加完成之後,我們就不用在搜尋欄中輸入相應的TAG了,取而代之的是,直接點選右上角的過濾器,選擇我們添加進去的TAG即可。
折疊資訊
為了友善講解,我在監聽中的
onScrollStateChanged(...)
方法裡,使用同一個TAG向控制台列印一條資訊:
Log.d("recycler_view", "state:" + newState)
,如下圖所示:
此時我們隻想檢視有關它state的值,并不關心其他資訊。那麼我們可以選中那些多餘且不關心的子字元串,右鍵它,點選
Fold lines like this
。這樣就為我們建立了一個過濾器。
可以折疊所有包含我們選中的子字元串的字元串! 留下我們關心的資訊:
現在我們再回過頭看看剛才列印出來的這些Log,是不是頓時覺得眼睛輕松了很多!當然點選紅圈裡面的‘+’,可以随時展開或折疊。
Debug斷點跟蹤調試技巧
基本使用
啟動Debug有兩種方式,一種是點選
Debug
,即中間的那隻小蟲子,另一種是點選
Attach debugger to Android process
,即靠近右邊帶箭頭的小蟲子。
一般我推薦使用
Attach debugger to Android process
來進入調試模式,它能夠在App處于運作狀态時進入調試模式,而要是通過
Debug
進入調試,它會停止應用并重新開機。這樣我們還需要一路尋找回我們需要調試的狀态,就稍微有點煩心了。
我們點選帶箭頭的小蟲子,彈出
Choose Process
視窗,選擇對應程序,點選‘OK‘按鈕,進入調試模式。
現在我們可以在代碼中打上斷點,打斷點的方法就是點選目标行代碼行号右側的空白處,再點選一次就是取消斷點,斷點是可以上下拖動。
當App在運作時,如果擊中了斷點,則會在Debug視窗中顯示斷點資訊。
工具欄操作按鈕
接着,來了解下Debug的操作按鈕:
斷點管理區操作按鈕:
順序從上到下:
-
:一是可從目前斷點移動到下一個斷點,斷點間的代碼自動執行;二是讓App從暫停狀态恢複到運作狀态。Resume Program
-
:暫停App。Pause Program
-
:對于普通的JAVA項目則是退出調試,對于Android項目則是結束App運作。Stop
-
:檢視所有斷點,并可以管理配置斷點的行為。View Breakpoints
-
:切換啟用或禁用所有斷點的狀态。Mute Breakpoints
-
:進入線程Dunmp界面。Get Thread Dump
調試區操作按鈕:
順序從左往右:
-
:定位到正在被執行的斷點位置。Show Excution Point
-
:單步執行,即前進到下一行代碼。Step Over
-
:進入調用方法的第一行,不能跳到類庫方法。Step Into
-
:與Force Step Info
方法類似,隻不過他能跳到類庫的方法裡。Step Into
-
:前進到目前方法之外的下一行,可與Step Out
配合使用。Step Into
-
:傳回到方法執行的初始點(下方有示範)。Drop Frame
-
:跳轉到光标所在處,需要目前斷點已經執行到最後一個,且光标所在的代碼行要符合由上到下的執行順序,不能颠倒。Run to Cursor
Drop Frame:可以用來在調試的時候,原本想點選
Step Into
進入方法内部看看,卻不小心點了
Step Over
向下走了一行。如果調試運作的裝置是Android10以上的版本,那麼我們可以點選
Drop Frame
按鈕——它的作用是可以把我們從目前方法拉出來,放回方法開始前的地方。接着點選
Resume Program
按鈕,就相當于擷取到了一次重新開始的機會!示範如下:
條件斷點
我們把斷點打到循環體裡的某行代碼,想看看循環到某一次時的運作狀态。難道此時我們要不停的點
Resume Program
按鈕,直到跳轉到滿足我們要求的斷點嗎?
不,當然不需要。假如我們想檢視斷點在運作到第二十次時的狀态,可以右擊這個斷點,在彈出的視窗中的
Condition
裡加入任何布爾表達式:
i==20
(可以選擇語句的語言),點選‘Done’按鈕完成配置:
如果條件為“true”,當代碼命中這個條件時,那麼就會到達這個斷點!
日志斷點
App在運作時擊中我們打上的斷點,立馬會把斷點資訊顯示在在
Variables
菜單中,然後我們就需要在整個菜單中找出我們想要的資訊:
這樣有時還蠻麻煩的,我們真正想做的是直接在代碼中打上Log,但卻不想把Log語句在代碼中打得到處都是,這時日志斷點就派上用場了!
操作步驟:右擊需要打Log的斷點,在它彈出的視窗中取消選中
Suspend
(下面會介紹到),此時視窗會向下展開一些新内容。我們勾選
Evaluate and log
選項,并在其中添加上Log語句,點選‘Done’按鈕。
現在,當線程遇上這個斷點的時候并不會停止,它隻會計算斷點裡的Log表達式,并把它記錄到控制台,然後繼續運作。
異常斷點
想必App在運作的過程中遇到各式各樣未知性的異常導緻的Crash常常令你抓狂,不過強大的Android Studio提供了異常斷點的功能。幫助我們在調試運作的App遇到異常,能夠先快速準确的定位到産生異常的地方,而非第一時間停止App的運作。
我們點選斷點區工具欄上面的
View Breakpoints
按鈕,呼出斷點管理界面。然後點選‘+’,選擇
Java Exception Breakpoints
。如下圖所示:
點選後呼出
Enter Exception Class
界面,我們在搜尋欄中填入想要監控異常的關鍵字。Java代碼選擇
NullPointerException
,Kotlin代碼選擇
KotlinNullPointerException
,點選‘OK’按鈕即可,如下圖所示:
不過!!在我模拟空指針異常的時候發現,如果用Java代碼寫的話,調試器确實能監控的到異常,并能定位産生異常的代碼。但是!!我用Kotlin寫的話,App直接Crash掉了。并未監控到異常,也沒定位到産生異常的代碼。
不知道是我調試姿勢有問題,還是暫時不支援Kotlin代碼。
變量指派
可以讓我們在調試期間,通過更改斷點監控到變量的值,來改變App執行的結果!
具體操作如下:
首先我們在擷取資料的循環體裡打上斷點。如下圖所示:
通過
Debug
進入調試模式,在
Variables
菜單中,選中我們要改變的變量,右擊它,在打開的選項中點選
Set Value...
。如下圖所示:
我們把
i=1
更改為
i=28
,此時能清楚得看到,在代碼中顯示的變量i資訊也從
i:1
變成了
i:28
。如下圖所示:
在循環中,原本變量i的值是從1到30,但我們已經把初始i的值改為了28,點選斷點區工具欄上的
Resume Program
按鈕,原本需要循環30下才執行完畢的斷點現在點3下便可完成。
現在來看看更改變量值後App的情況吧:
Suspend 選項
在我們右擊斷點的時候,你可能留意到這的
Suspend
選項,如下圖所示:
目前我們“All”與“Thread”之中選擇了“All”,意味着在目前執行線程遇到該斷點的時候,會停止App内的所有線程,這樣就會停止App整個運作狀态。
但是如果你正在處理一個多線程App,而你正在尋找一些特别麻煩的異步問題,你可以試着隻去暫停那個撞到斷點的線程。可把選中“All”改為選中“Thread”。
直到擊中某一斷點才啟用
為了友善舉例,我在示例中RecyclerView的滑動監聽裡面與按鈕的點選監聽中分别打上斷點。
由于斷點被打在RecyclerView的滑動監聽裡,那麼我們手指稍微一滑動,就會立即執行該斷點。那麼在調試的時候我想必須先擊中按鈕監聽裡面的斷點,才允許執行RecyclerView的滑動監聽裡面的斷點。
此時,
Disable until breakpoint is hit
功能就派上用場了。
右擊RecyclerView的滑動監聽裡斷點,在彈出的視窗裡面點選
More
:
我們就會進入到斷點管理界面,在該斷點的
Disable until breakpoint is hit
選項中,禁用斷點,直到我們選擇的按鈕監聽裡斷點被命中為止。如下圖所示:
現在手指滑動螢幕的時候并不會觸發RecyclerVie滑動監聽裡面的斷點,直到點選了按鈕,觸發了點選監聽裡面的斷點,才被激活一次。意味着每次執行完該斷點,就會被禁用掉,除非再點選一次按鈕才被重新激活。示範如下:
禁用斷點
當已被打上的斷點,我們暫時不需要命中它的時候,我們可以把它給禁用掉,右鍵斷點,在彈出的視窗來取消勾選
Enable
選擇。此時斷點會變成一個空心圓。不過更友善的做法是通過“Alt + 點選”,Mac是“Opt + 點選”。這樣就能讓它在開/關的狀态下切換:
斷點組
有時候我們在執行調試App功能的時候會遇到一些暫時不需要使用的斷點,我們又不想把它們删掉,也許調試下個功能可能會用上,是以隻能一個一個禁掉它們。
其實,隻要我們學會使用斷點組,這就友善多了!
右鍵斷點,點選視窗的
More
,前往斷點管理界面。我們還可以點選Debug視窗裡的斷點區工具欄中的
View Breakpoint
按鈕也能前往。
在該界面中,可以看到所有斷點都在上面。我們多選它們,右擊,建立一個新的組,你可以把它們起名為你正在處理Bug的名字。
這裡我起名為OnScrollListener,意味着該組的斷點都來自
addOnScrollListener(...)
的監聽裡。如下圖所示:
分組完畢後,你可以通過點選組的單選框來切換組内斷點開/關的狀态。當你處理完Bug後,可以選中組,并點選“-”,即可把它們全部删掉。如下圖所示:
Evaluate expression
系統給
Variables
區的變量對象提供了表達式求值的功能。在抵達斷點後,如果有變量對象。我們可以輸入任何表達式,來實時檢視表達式的計算結果。
首先,可通過點選工具欄上面的
Evaluate expression
按鈕,或者右鍵目标代碼選擇
Evaluate expression
來呼出操作界面。如下圖所示:
一般首次打開它的時候,是單行輸入模式,我們輸入一條
textList[position]
,點選‘Evaluate’按鈕,就能在下方
Result
中浏覽對象。如下圖所示:
如果我們想輸入更加豐富的表達式,那麼單行模式不能滿足我們的需求。點選輸入框的右上角,将單行模式擴充為多行。這樣,我們就能夠輸入更加豐富的表達式:
Evaluate expression 是非常适合充當實時檢測器,它能夠讓我們清楚的觀察到目前應用的狀态。
分析堆棧軌迹
在合作開發項目中,也許我們會收到來自同僚發來的一份包含調用棧的Bug報告,其實也就是一堆文本。我們複制Bug報告,回到Android Studio,點選工具欄上面的
Analyze
,然後點選
Analyze Stack Trace...
,我們會發現它找到了粘貼闆上面的内容:
點選‘OK’按鈕後,它會對我們的調用棧作一個全面的注解,并顯示在控制台中。我們點選其中的連結,就會對我們的代碼庫進行一個快速的檢索并定位代碼:
總結
本篇文章大部分内容來自谷歌官方的視訊Android Studio: 調試的技巧與心得,我推薦大家可以關注下谷歌的官方賬号。裡面有很多優質的視訊,都是由開發者本人來講解的。
希望本文能給大家在調試App的時候提供多一條思路。
參考
感謝以下資料,讓我站在了巨人的肩膀
- Android Studio: 調試的技巧與心得
- Android Studio 掌握這些調試技巧,Debug 能力不能再高啦
- 你所不知道的Android Studio調試技巧
- Android Studio官方文檔–調試應用