本文通過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的操作按鈕:
斷點管理區操作按鈕:
順序從上到下:
Resume Program
:一是可從當前斷點移動到下一個斷點,斷點間的程式碼自動執行;二是讓App從暫停狀態恢復到執行狀態。Pause Program
:暫停App。Stop
:對於普通的JAVA專案則是退出除錯,對於Android專案則是結束App執行。View Breakpoints
:檢視所有斷點,並可以管理配置斷點的行為。Mute Breakpoints
:切換啟用或禁用所有斷點的狀態。Get Thread Dump
:進入執行緒Dunmp介面。
除錯區操作按鈕:
順序從左往右: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的時候提供多一條思路。
參考
感謝以下資料,讓我站在了巨人的肩膀