標籤:
前言
安卓開發的過程中,需要對開發的程式進行調試。Google官方和非官方,提供了很多協助我們調試代碼的工具和方法。有的使用起來很簡單,有的則功能強大,很少有機會接觸。因此,我們打算由淺入深的向同學們介紹,知道針對不同的情境,使用合適的工具。
本文針對的讀者是:
- 對安卓程式調試需要指導的新手;
- 對程式調試沒有太多經驗的開發人員;
在開始以前,假設各位已經做好了如下準備:
- 已經在搭建好了安卓軟體開發平台
- 一部安卓系統裝置(手機或平板電腦);
- 一根串連電腦和安卓裝置的資料線(通常是micro usb資料線);
- 半天時間。
- 耐心與求知慾。
本文將介紹到:
- 斷點調試;
- 輸出log調試;
- Android Device Monitor初步使用
- ADB工具
- wifi串連裝置調試;
第1節 動態調試與靜態調試
安卓系統上偵錯工具,主要通過兩種形式:
1. 靜態調試:程式在運行到某一個狀態的時候,讓它暫停,用工具查看程式此時的運行資訊,比如某個變數的數值;查看完成後,讓程式繼續運行,恢複到正常的工作。
2. 動態調試:在程式中,添加日誌資訊(log),在程式啟動並執行時候,將log指定的資訊輸出到調試的電腦上。整個過程不會打斷程式的運行。
不管哪種調試方式,都需要手機與調試的電腦通過資料線相連,藉此傳遞調試資訊。
1.1 裝置與電腦的串連
要在裝置上進行調試,首先要開啟裝置的開發人員選項,不同品牌的安卓裝置介面雖然不盡相同,但使用方式都大同小異:
- 啟動安卓裝置上的“設定”應用,進入“關於手機”選項卡;
連續點擊“版本號碼”,直到出現您現在處於開發人員模式!的提示資訊;
返回上級菜單,進入“開發人員選項”,開啟偵錯模式,鉤上USB調試;
將手機和電腦用USB資料線串連起來。
在Windows系統,需要為串連上的裝置安裝ADB驅動:
- 在安豆網的資源下載下載ADB的Windows驅動到電腦本地;
- 在“我的電腦”上點滑鼠右鍵,選擇“管理”,開啟“裝置管理員”,可以看到沒有安裝驅動的裝置;
為它更新驅動,選擇“瀏覽電腦尋找”,
指定下載的ADB驅動目錄位置,點擊確定後,驅動很快就安裝成功了。
點擊Android Studio的Android Monitor視窗,就能看到這個串連上的裝置了,這個視窗還輸出了手機端列印的運行資訊。
1.2 部署應用
將應用程式通過Android Studio運行到裝置上有兩個方式:run app和debug app。
debug app可以設定斷點,進行代碼的靜態調試;而run app不能設定斷點,不能對代碼進行靜態調試。這兩種方式可以通過功能表項目啟動,也可以通過快速鍵開始。
點擊功能表列中的綠色的小三角,就是run app;
或者使用debug app的快捷按鍵shift+F10;
在選定的裝置上雙擊,
此時就可以在裝置上看到,我們的程式運行起來了。
1.3 靜態調試方法
靜態調試就是凍結應用啟動並執行狀態,彷彿時間停止了一般,然後我們逐一觀察此時程式的各個參數是否符合我們的預期。這種調試方法適用於對時間不敏感的程式。也就是說被調試的程式線程不需要依賴別的線程,即使暫時停止工作也不會影響別的背景工作執行緒或者受別的背景工作執行緒影響。
在希望代碼暫停啟動並執行地方打斷點——在代碼前點擊一下,出現一個紅色的圓點,如果想取消,再點擊一次即可。
用debug run的方式部署程式。當程式運行到這段代碼的這個位置時,程式將停止下來,切換到Debug視窗。這時,我們就可以觀察各個參數了。例如右半地區就列出了停止時,各個變數的值;左邊地區展示了當時函數到調用棧(誰調用的這個函數)情況。我們可以逐一分析,詳細觀察,看這些值是否符合我們的預期。
下面的功能,將指定程式暫停後,執行下一步的走向。這些都是斷點調試經常使用到的、由我們控製程序運行步驟的功能,所以盡量記住它們對應的捷徑;
Step Over:執行完成當前斷點停留處的代碼,然後停在下一行待執行的代碼處。
void fun1(){ int a = 0; fun2(); //正等待執行的代碼 a++; //下一步待執行的代碼}void fun2(){ int b = 0; b++;}
Step Into:如果當前斷點執行處是一個函數,那麼執行Step Into後,進入到該函數。
void fun1(){ int a = 0; fun2(); //正等待執行的代碼 a++;}void fun2(){ int b = 0; //下一步待執行的代碼 b++;}
Step Out:在當前斷點執行處執行Step Out後,返回到調用該函數的地方等待執行。
void fun1(){ int a = 0; fun2(); //下一步待執行的代碼 a++;}void fun2(){ int b = 0; //正等待執行的代碼 b++;}
Resume Program:程式繼續往下執行,直到遇到下一個斷點。
有的調試功能帶有force,例如force step over,它們可以在這種情境下使用:當你想進入不是你寫的原始碼查看調用過程,但是使用不帶force的功能,卻沒有起作用。簡單來說就是不帶force的用來跟蹤自己寫的代碼,帶force的用來跟蹤SDK裡的源碼。
1.4 動態調試方法
對於那些和時間相關的程式(不能讓程式暫停,等你慢慢觀察),我們就不能使用靜態調試方法了,得採用動態調試,添加log的方式。
Log的中文名字叫做日誌,在編程界表示程式運行過程中列印出的資訊。根據log我們就知道現在程式運行到什麼地方了,log還可以攜帶程式中某些變數的資訊輸出,讓我們更精準的知道程式當前啟動並執行狀態。
1.4.1 代碼中添加log
在代碼中添加一段函數,就能通過特別的工具輸出這些log。
在Android代碼中添加log的方式如下:
@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.d("TAG", "debug info: function=" + "onCreate()");}
這裡面使用了Android提供的Log庫。
1.4.2 log的查看
添加了log資訊後,將程式通過debug app部署到裝置上,就能在Android Monitor工具的logcat視窗中看到對應的資訊了。
輸出的調試資訊如下:
03-22 03:22:39.778 8357-8357/com.anddle.calculator D/TAG: debug info: function=onCreate()
03-22 03:22:39.778:log產生的時間;
8357-8357:裝置上運行這段代碼的進程ID(PID)和線程ID(TID);
com.anddle.calculator:裝置上運行這段代碼的包名;
D:這條log的類型。我們輸出這條log使用的是Log.d(),所以就顯示D;如果使用Log.i()就顯示I,以此類推;
TAG:就是Log.d()函數的第一個參數;
debug info: function=onCreate():就是Log.d()函數的第二個參數;
Android應用開發的Log庫提供了幾種不同等級的log:Verbose Debug Info Warining Error,我們可以根據自己log的需要加不同等級的log,使用的形式為:
Log.v(“TAG”,”content is verbose”);Log.d(“TAG”,”content is debug”);Log.i(“TAG”,”content is info”);Log.w(“TAG”,”content is waring”);Log.e(“TAG”,”content is error”);
我們在應用中偵錯工具,通常使用d。
1.4.3 log的添加規則
在應用的開發當中,我們對log的添加有一些不成文的技巧,可以提高程式的開發效率。
在調試應用的同一個功能時,為它定義同一個TAG。例如,一個應用有網路通訊和本地檔案讀取兩個大功能。那我們就可以為有網路通訊定義一個TAG叫做Network,為另一個本地檔案讀取定義一個TAG叫做FileAccess。這樣當我們查看對應的log資訊時,就很容易通過關鍵字把它們從log的海洋裡區分開。將TAG定義成一個字串常量,便於對log輸出資訊的修改。
static final String TAG1 = "Network";static final String TAG2 = "FileAccess";......Log.d(TAG1,"這是網路通訊相關的log!");Log.d(TAG2,"這是檔案讀取的log!");
使用Debug開關控制log資訊是否輸出。在調試應用的時候要添加很多log,當應用發布的時候,又要去掉這些log資訊。添加或者刪除這些log,會增加很多工作。所以我們需要使用Debug開關。
static final boolean DEBUG = true; //true表示開啟開關,false表示關閉開關;......if(DEBUG){ Log.d(TAG,"Debug開關開啟才輸出!");}
輸出函數的調用棧。有的時候,我們不僅關注程式執行到當前時各個變數的值是什麼,還關心這個函數是怎麼被調用到的。那麼我們可以在代碼中,添加輸出調用棧的資訊:
Log.d(TAG, Log.getStackTraceString(new Throwable()));
Log.d()在調試代碼時使用,用Debug開關控制;Log.e()在出現意外而重要的錯誤情況時使用,不用Debug開關控制;Log.v() Log.i()和Log.w()在需要輸出運行狀態並且不涉及暴露應用實現資訊的情況時使用,不必用Debug開關控制;當然,開發人員想怎麼用這些log類型就可以怎麼用,並沒有特別的約束。
AndroidStudio應用調試技巧(上)