程式除錯是程式投入執行之前,使用手工或編譯程式等方法進行的測試,z主要用以修正語法錯誤和邏輯錯誤。程式除錯是保證計算機資訊系統正確性的必不可少的步驟。 在Flutter應用開發中,Android Studio和VSCode是兩種比較常見的整合開發環境,因此專案除錯也圍繞這兩款IDE進行。Android Studio為Flutter提供完整的整合IDE體驗,因此Android的除錯技巧對於Flutter來說也是適用的。在 Flutter 中,除錯程式碼主要分為輸出日誌、斷點除錯和佈局除錯 3 類,因此Flutter的除錯也將圍繞這 3 個主題。
Android Studio
輸出日誌
為了便於跟蹤和記錄應用的執行情況,我們在開發時通常會在一些關鍵步驟輸出日誌(Log),在Flutter中我們使用 print 函式在控制檯列印出相關的上下文資訊。通過這些資訊,就可以定位程式碼中可能出現的問題。不過,由於涉及 I/O 操作,使用 print 來列印資訊會消耗較多的系統資源。同時,這些輸出資料很可能會暴露 App 的執行細節,所以我們在釋出正式版時還需要遮蔽掉這些輸出。
不過最工程化的做法是讀取專案配置檔案,根據執行環境來開啟日誌除錯功能。為了根據不同的執行環境來開啟日誌除錯功能,我們可以使用 Flutter 提供的debugPrint 來代替 print。debugPrint 函式同樣會將訊息列印至控制檯,但與 print 不同的是,它提供了定製列印的能力。也就是說,我們可以向 debugPrint 函式,賦值一個函式宣告來自定義列印行為。
比如在下面的程式碼中,我們將 debugPrint 函式定義為一個空函式體,這樣就可以實現一鍵取消列印的功能了。
debugPrint = (String message, {int wrapWidth}) {};//空實現
複製程式碼
在 Flutter 中,我們可以使用不同的 main 檔案來表示不同環境下的入口。同樣,在Flutter開發中,可以通過 main.dart 與 main-dev.dart,去分別定義生產環境與開發環境不同的列印日誌行為。
在下面的例子中,我們將生產環境的 debugPrint 定義為空實現,將開發環境的 debugPrint 定義為同步列印資料,如下所示。
//main.dart
void main() {
// 將debugPrint指定為空的執行體, 所以它什麼也不做
debugPrint = (String message, {int wrapWidth}) {};
runApp(MyApp());
}
//main-dev.dart
void main() async {
// 將debugPrint指定為同步列印資料
debugPrint = (String message, {int wrapWidth}) => debugPrintSynchronously(message, wrapWidth: wrapWidth);
runApp(MyApp());
}
複製程式碼
可以看到,在程式碼實現上,我們只要將應用內所有的 print 都替換成 debugPrint,就可以滿足開發環境下打日誌的需求,也可以保證生產環境下應用的執行資訊不會被意外列印。
斷點除錯
輸出日誌固然方便,但如果要想獲取更為詳細,或是粒度更細的上下文資訊,靜態除錯的方式非常不方便。這時,我們需要更為靈活的動態除錯方法,即斷點除錯。斷點除錯可以讓程式碼在目標語句上暫停,讓程式逐條執行後續的程式碼語句,來幫助我們實時關注程式碼執行上下文中所有變數值的詳細變化過程。
Android Studio 提供了斷點除錯的功能,除錯 Flutter 應用與除錯原生 Android 程式碼的方法完全一樣,具體可以分為三步,即標記斷點、除錯應用、檢視資訊。
下面以 Flutter 預設的計數器應用模板為例,觀察程式碼中 _counter 值的變化,體會斷點除錯的全過程。
首先是標記斷點。既然我們要觀察 _counter 值的變化,因此在介面上展示最新的 _counter 值時新增斷點,去觀察其數值變化是最理想的。因此,我們在行號右側點選滑鼠,可以把斷點載入到初始化 Text 控制元件所示的位置。
在下圖的例子中,我們為了觀察 _counter 在等於 20 的時候是否正常,還特意設定了一個條件斷點 _counter==20,這樣偵錯程式就只會在第 20 次點選計數器按鈕時暫停下來。
新增斷點後,對應的行號將會出現圓形的斷點標記,並高亮顯示整行程式碼。到此,斷點就新增好了。當然,我們還可以同時新增多個斷點,以便更好地觀察程式碼的執行過程。
接下來則是除錯應用了。和之前通過點選Run 按鈕的執行方式不同,這一次我們需要點選工具欄上的蟲子圖示,以除錯模式啟動 App,如下圖所示。
等偵錯程式初始化好後,我們的程式就啟動了。由於設定了斷點,所以當程式碼執行到了斷點位置,自動進入了 Debug 檢視模式,如下圖所示。 按照功能的不同,可以把 Debug 檢視模式劃分為 4 個區域,即 A 區控制除錯工具、B 區步進除錯工具、C 區幀除錯視窗、D 區變數檢視視窗。控制除錯工具區域主要用來控制除錯的執行情況,如下圖所示。
我們可以點選繼續執行按鈕來讓程式繼續執行、點選終止執行按鈕來讓程式終止執行、點選重新執行按鈕來讓程式重新啟動,或是在程式正常執行時,點選暫停執行按鈕按鈕來讓程式暫停執行。當然,我們可以點選編輯斷點按鈕來編輯斷點資訊,或是點選禁用斷點按鈕來取消斷點。 步進除錯工具區域主要用來控制斷點的步進情況,如下圖所示。 可以點選單步跳過按鈕來讓程式單步執行(但不會進入方法體內部)、點選單步進入或強制單步進入按鈕讓程式逐條語句執行,甚至還可以點選執行到游標處按鈕讓程式執行到在游標處。認為斷點所在的方法體已經無需執行時,則可以點選單步跳出按鈕讓程式立刻執行完當前進入的方法,從而返回方法呼叫處的下一行。擔任,還可以點選表示式計算按鈕來通過賦值或表示式方式修改任意變數的值。C 區用來指示當前斷點所包含的函式執行堆疊,D 區則是其堆疊中的函式幀所對應的變數。
佈局除錯
除了輸出日誌、斷點除錯,佈局分析也是開發中不可缺少的程式碼優化手段。藉助Flutter提供的Flutter Inspector 視覺化工具,可以幫助我們診斷佈局問題。開啟Android Studio,然後點選工具欄上的“Open DevTools”按鈕即可啟動 Flutter Inspector,如下圖所示。
隨後,Android Studio 會開啟瀏覽器,將Flutter應用程式的的 Widget 樹結構展示在皮膚中。可以看到,Flutter Inspector 所展示的 Widget 樹結構,與程式碼中實現的 Widget 層次是一一對應的。 除了進行佈局除錯外,還可以使用Flutter Inspector進行佈局調優。VSCode
除了Android Studio外,VSCode也是一款比較常見的Flutter應用程式開發工具。使用VSCode提供的圖形化除錯介面,開發者可以很方便的進行Flutter應用的除錯工作。使用VSCode開啟Flutter專案,然後點選VSCode的斷點除錯按鈕即可開啟除錯,如下圖所示。
需要說明的是,第一次使用VSCode進行斷點除錯時,需要先安裝並啟用Dart DevTools除錯工具。如果不確定是否繫結過DevTools工具,可以使用快捷鍵【command+shift+p】開啟VSCode工具欄,然後輸入Open DevTools開啟除錯視窗。 然後,在需要除錯的程式碼處設定斷點,點選左上方的開啟除錯按鈕開啟除錯即可。當程式碼執行到斷點處時,就會停留在斷點處,然後就可以進行相關除錯操作。