上一篇文章中我們講解了Android UI優化方面的知識。我們講解了Android中的include、marge、ViewStub標簽,在使用這些標簽時可以簡化我們的布局文件,優化組件繪制流程;講解了Android中的過度繪制相關知識點,通過優化我們的App過度繪制可以提高App的UI繪制流程與性能;我們還講解了App中一些UI優化的小tips。更多關于Android UI優化方面的知識可以參考我的:[Android產品研發(二十一)–>Android中的UI優化](http://blog.csdn.net/qq_23547831/article/details/51868453)
本文我們將講解Android中的調試技巧。程序調試,是將編制的程序投入實際運行前,用手工或編譯程序等方法進行測試,修正語法錯誤和邏輯錯誤的過程。這是保證計算機信息系統正確性的必不可少的步驟。在Android開發過程中熟練的使用調試技巧是一個很重要的方面。Android的調試技巧包括熟練使用Android中的日志API,自定義Android日志框架,通過gradle配置調試日志,Android studio的調試技巧等等。通過對本文的學習我們能夠對Android中調試技巧有一個大概的了解。
**Android中的打印API:**
我們首先來看一下Android中提供的打印日志API:
~~~
Android.util.Log.java
~~~
這個類比較常用的打印日志的方法有5個,這5個方法都會把日志打印到AndroidMonitor中,Android中日志分為五個級別:
* Log.v(tag,message); //verbose模式,打印最詳細的日志
* Log.d(tag,message); //debug級別的日志
* Log.i(tag,message); //info級別的日志
* Log.w(tag,message); //warn級別的日志
* Log.e(tag,message); //error級別的日志
其中tag和message分別是兩個String值.從Android開發幫助文檔中來看,tag和message的定義分別是:
~~~
tag:Used to identify the source of a log message. It usually identifies the class or activity where the log call occurs.
msg:The message you would like logged.
~~~
可看出tag用來標記log消息的源頭的。而message則是這條log的內容.
- 一個簡單的Log API例子
Log demo代碼:
~~~
/**
* 按鈕點擊事件,打印各個級別的日志
*/
button6.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.v(TAG, "this is a verbose log!!!");
Log.d(TAG, "this is a debug log!!!");
Log.i(TAG, "this is a info log!!!");
Log.w(TAG, "this is a warning log!!!");
Log.e(TAG, "this is a error log!!!");
}
});
~~~
好吧,我們點擊按鈕,看一下AndroidMonitor中的打印結果:
~~~
07-17 19:22:16.202 7530-7530/uuch.com.Android_activityanim V/MainActivity: this is a verbose log!!!
07-17 19:22:16.202 7530-7530/uuch.com.Android_activityanim D/MainActivity: this is a debug log!!!
07-17 19:22:16.202 7530-7530/uuch.com.Android_activityanim I/MainActivity: this is a info log!!!
07-17 19:22:16.202 7530-7530/uuch.com.Android_activityanim W/MainActivity: this is a warning log!!!
07-17 19:22:16.203 7530-7530/uuch.com.Android_activityanim E/MainActivity: this is a error log!!!
~~~
通過這種Android自身Log API打印日志的方式,是最常見的一種打印日志的,調試代碼的方式,基本上所有的項目中你可能都會遇到這種日志代碼,前面的一篇文章中我也分析了Log日志的部分源碼,具體可參考我的:[Android源碼解析之(六)–>Log](http://blog.csdn.net/qq_23547831/article/details/50963006)
但是呢你會發現這時候打印的日志格式比較簡陋,比如出現異常的時候我們想快速定位到代碼在哪,這時候就比艱難了,所以下面我們講一下自定義日志框架。
**自定義Android打印框架MLog**:
前面我們發現使用Android原生的Log API打印的日志格式比較簡陋,那么可不可以定制化的顯示一些友好型的日志信息呢?答案是肯定的,在前面的文章中我介紹了一個自定義的日志框架MLog,可參考我的:[github項目解析(五)–>Android日志框架](http://blog.csdn.net/qq_23547831/article/details/51707796)
關于MLog框架的使用方式,實現過程等已在文章中做過簡單的介紹,這里就看一下其打印的日志格式:
**自定義按鈕點擊事件**:
- 在Application中初始化MLog框架
~~~
/**
* 傳入為true,則表示執行打印操作,否則不顯示日志
*/
MLog.init(true);
~~~
盡量可以在Application的onCreate方法中執行,這是App的進程起始方法。
- 在源代碼中執行打印日志的操作
~~~
/**
* 自定義按鈕的點擊事件
*/
button6.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MLog.v(TAG, "this is a verbose log!!!");
MLog.d(TAG, "this is a debug log!!!");
MLog.i(TAG, "this is a info log!!!");
MLog.w(TAG, "this is a warning log!!!");
MLog.e(TAG, "this is a error log!!!");
}
});
~~~
在AndroidMoitor中打印的日志格式和內容:

這樣我們在點擊日志信息的時候就能夠跳轉到這條日志的代碼打印位置,是不是很方便?而且如果覺得日志格式不是很好的話,還可以定制化展示奧。
比如:

怎么樣?是不是很好看了?
具體如何實現自定義Log框架以及自定義實現Log的顯示樣式可以參考我的:[github項目解析(五)–>Android日志框架](http://blog.csdn.net/qq_23547831/article/details/51707796)
大多時候我們的App都有測試環境和正式環境兩種環境的,當切換環境的時候要求我們在測試環境打印日志,則正式環境屏蔽日志,通過代碼也可以實現,但是比較麻煩,有沒有一個比較簡單的方法呢?答案是肯定的,可以通過配置gradle的方式配置在測試環境中打印日志,在正式環境中屏蔽日志打印操作。
**gradle中配置正式測試打印框架**:
我們知道在Android開發過程中為了調試代碼經常在代碼中添加一些日志信息,但是正式環境是不需要這些日志信息的,而且過得日志打印操作也會對App的性能有影響。
一個比較好的辦法就是在App的測試環境中打印日志信息,在正式環境中屏蔽日志信息,那么如何實現呢?通過代碼么?通過代碼也是可以實現的,但是這樣顯得太原始了,其實Android studio的gradle插件已經提供了這樣的功能。
那么如何通過gradle配置日志打印信息呢?
~~~
buildTypes {
debug {
// 顯示Log
buildConfigField "boolean", "LOG_DEBUG", "true"
//混淆
minifyEnabled false
//Zipalign優化
zipAlignEnabled true
// 移除無用的resource文件
shrinkResources true
//加載默認混淆配置文件
proguardFiles getDefaultProguardFile('proguard-Android.txt'), 'proguard-rules.pro'
//簽名
signingConfig signingConfigs.debug
}
release {
// 不顯示Log
buildConfigField "boolean", "LOG_DEBUG", "false"
//混淆
minifyEnabled true
//Zipalign優化
zipAlignEnabled true
// 移除無用的resource文件
shrinkResources true
//加載默認混淆配置文件
proguardFiles getDefaultProguardFile('proguard-Android.txt'), 'proguard-rules.pro'
//簽名
signingConfig signingConfigs.relealse
}
}
~~~
在Android studio的module的gradle配置文件中,在buildTypes節點下可以配置自定義參數,這里我們在debug版本中定義LOG_DEBUG為true,在release版本中定義LOG_DEBUG為false。這樣在編譯的時候就會在gradle的編譯類BuildConfig中生成成員變量:
~~~
LOG_DEBUG
~~~
* 若是正式環境則LOG_DEBUG的值為false
* 若是測試環境則LOG_DEBUG的值為true
所以這時候可以通過LOG_DEBUG變量的值控制日志是否打印。
~~~
/**
* 在Application的onCreate方法中初始化MLog日志框架
* 并根據apk環境判斷是否顯示日志信息
*/
if (BuildConfig.LOG_DEBUG == true) {
MLog.init(true);
} else {
MLog.init(false);
}
~~~
我們實現的MLog框架的init方法
* 若傳入的值為true,則表示執行日志打印操作,也就是可以顯示日志信息。
* 若傳入的值為false,則表示不執行日志打印操作,也就是不顯示日志信息。
這樣我們就實現了在測試環境打印日志,在正式環境中屏蔽日志的操作。
**Android studio的調試技巧**:
寫代碼的過程中不可避免有Bug,通常情況下除了日志最直接的調試手段就是debug;那么你的調試技術停留在哪一階段呢?僅僅是下個斷點單步執行嗎?你是否知道求值調試,條件斷點,日志斷點,方法斷點,異常斷點等調試技巧么?下面我們將介紹一下Android studio中的調試技巧。
**調試基礎**
一般來說我們有兩種辦法調試一個debuggable的apk;
**設置好斷點,然后用debug模式編譯安裝這個app;
執行attach debugger to Android process,即將debug進程添加到當前進程中。**
一般比較常使用的debug方式是attach debugger to Android process:

在執行按鈕右側兩個的帶有小蟲子的按鈕其實就是Attach Debugger to Android process按鈕。
我們可以在啟動apk之后,直接下斷點,然后attach process到指定進程,條件觸發之后就可以直接進入調試模式。
**斷點調試**
斷點調試是最基本操作,基恩的斷點調試有以下的幾個常用的調試命令:
* F5跳轉內部執行
* F6跳轉下一步
* F8跳轉到下一個斷點
**如何添加斷點?**
直接在Android studio中的java源代碼左側,想調試某一行代碼的話,直接單擊若左側出現了一個小紅圈,則說明斷點已經添加好了:

當代碼處于debug模式,并且執行到此處的時候就會卡住在這里。
**執行斷點調試**
執行attach debugger to Android process,當代碼執行到含有斷點的時候就可以將程序卡到斷點的代碼了:

這時候我們可以看到在該行代碼中可以看到相應的局部變量值,執行F6走到下一步,執行F8,調試到下一個斷點。
**添加觀察變量**
在調試模式下,選擇變量,并右擊:

這時候選擇Add to watches,就可以將變量添加到觀察列表了。
**表達式調試:Evaluate Expression**
這個調試功能非常的實用,也是我最喜歡的功能,使用ctrl + u快捷鍵可以彈窗表達式調試彈窗:

這個功能非常實用,可以在斷點處直接進入一個求值環境,在這里你可以執行任何你感興趣的表達式可以在表達式調試彈窗中寫任何java表達式,比如:

其他的比如在斷點處有一個對象object,如果你要查看它的某個屬性很簡單,在Debug窗口就能看到,但是如果你想要執行它的某個方法看看結果是什么呢?借助這個可以實現。當然它的功能遠不止這么多,相當于直接進入了一個 REPL環境,非常實用。
**條件斷點**
假設你的斷點在一個列表的循環里面,可是你只對這個列表的某一個元素感興趣,只想在遇到這個元素的時候才斷下來;你是一直人肉 F9 直到滿足條件嗎?條件斷點就是滿足這種需求的,顧名思義,在特定條件下的斷點。使用起來也非常簡單,在你的斷點上鼠標右鍵會出現一個小窗口,寫上條件即可。

**其他斷點調試方式**
除了這里的求值斷點,條件斷點,還有日志斷點,異常斷點,方法斷點等,具體的可自行google哈。
**總結**:
* Android默認提供了Log API實現對日志的打印功能;
* 可以實現自定義日志框架,定制化顯示日志樣式,定制化配置是否顯示日志等,可參考:Android日志框架
* 可以通過配置gradle,讓測試環境中顯示日志信息,在正式環境中不顯示日志信息;
* Android studio提供了斷點調試功能,包含了求值調試,條件斷點,日志斷點,方法斷點,異常斷點等等;
另外對產品研發技術,技巧,實踐方面感興趣的同學可以參考我的:
[Android產品研發(十一)–>應用內跳轉scheme協議](http://blog.csdn.net/qq_23547831/article/details/51685310)
[Android產品研發(十二)–>App長連接實現](http://blog.csdn.net/qq_23547831/article/details/51719389)
[Android產品研發(十三)–>App輪詢操作](http://blog.csdn.net/qq_23547831/article/details/51764773)
[Android產品研發(十四)–>App升級與更新](http://blog.csdn.net/qq_23547831/article/details/51764773)
[Android產品研發(十五)–>內存對象序列化](http://blog.csdn.net/qq_23547831/article/details/51779528)
[Android產品研發(十六)–>開發者選項](http://blog.csdn.net/qq_23547831/article/details/51809497)
[Android產品研發(十七)–>hybrid開發](http://blog.csdn.net/qq_23547831/article/details/51812985)
[Android產品研發(十八)–>webview問題集錦](http://blog.csdn.net/qq_23547831/article/details/51820139)
[Android產品研發(十九)–>Android studio中的單元測試](http://blog.csdn.net/qq_23547831/article/details/51868451)
[Android產品研發(二十)–>代碼Review](http://blog.csdn.net/qq_23547831/article/details/51833080)
[Android產品研發(二十一)–>Android中的UI優化](http://blog.csdn.net/qq_23547831/article/details/51868453)
- 前言
- (一)–>實用開發規范
- (二)-->啟動頁優化
- (三)-->基類Activity
- (四)-->減小Apk大小
- (五)-->多渠道打包
- (六)-->Apk混淆
- (七)-->Apk熱修復
- (八)-->App數據統計
- (九)-->App網絡數據解析
- (十)-->盡量不使用靜態變量保存數據
- (十一)-->應用內跳轉Scheme協議
- (十二)-->App長連接實現
- (十三)-->App輪詢操作
- (十四)-->App升級與更新
- (十五)-->內存對象序列化
- (十六)-->開發者選項
- (十七)-->Hybrid開發
- (十八)-->webview問題集錦
- (十九)-->Android studio中的單元測試
- (二十)-->代碼Review
- (二十一)-->Android中的UI優化
- (二十二)-->Android實用調試技巧
- (二十三)-->Android中保存靜態秘鑰實踐
- (二十四)-->內存泄露場景與檢測
- (二十五)-->MVC/MVVM/MVP簡單理解