Android 2.3提供一個(gè)稱為嚴(yán)苛模式(StrictMode)的調(diào)試特性,Google稱該特性已經(jīng)使數(shù)百個(gè)Android上的Google應(yīng)用程序受益。那它都做什么呢?它將報(bào)告與線程及虛擬機(jī)相關(guān)的策略違例。一旦檢測(cè)到策略違例(policy violation),你將獲得警告,其包含了一個(gè)棧trace顯示你的應(yīng)用在何處發(fā)生違例。你可以強(qiáng)制用警告代替崩潰(crash),也可以僅將警告計(jì)入日志,讓你的應(yīng)用繼續(xù)執(zhí)行。策略的細(xì)節(jié)尚難確定,可以期待隨Android的成熟Google將增加更多策略。
目前有2種策略可用,第一個(gè)和線程相關(guān),它主要針對(duì)主線程(或UI線程)。由于在主線程中讀寫(xiě)磁盤(pán)和進(jìn)行網(wǎng)絡(luò)訪問(wèn)都不是好的做法,Google已經(jīng)在磁盤(pán)和網(wǎng)絡(luò)代碼中添加了嚴(yán)苛模式(StrictMode)鉤子(hook)。如果你對(duì)某個(gè)線程打開(kāi)嚴(yán)苛模式(StrictMode),當(dāng)那個(gè)線程進(jìn)行磁盤(pán)和網(wǎng)絡(luò)訪問(wèn),你將獲得警告。你可以選擇警告方式。一些違例包含用戶慢速調(diào)用(custom slow calls 這么翻譯行嗎?),磁盤(pán)讀寫(xiě),網(wǎng)絡(luò)訪問(wèn)。你能選擇將警告寫(xiě)入LogCat,顯示一個(gè)對(duì)話框,閃下屏幕,寫(xiě)入DropBox日志文件,或讓?xiě)?yīng)用崩潰。最通常的做法是寫(xiě)入LogCat或讓?xiě)?yīng)用崩潰。列表2-9顯示了一個(gè)為線程策略設(shè)置嚴(yán)苛模式(StrictMode)的例子。
列表2-9 設(shè)置嚴(yán)苛模式(StrictMode)的線程策略
StrictMode.setThreadPolicy(newStrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyLog()
.build());
Builder類使得設(shè)置變得很簡(jiǎn)單,Builder函數(shù)定義所有策略都返回Builder對(duì)象,從而這些函數(shù)能像列表2-9那樣串連在一起。最后調(diào)用build()函數(shù)返回一個(gè)ThreadPolicy對(duì)象作為StrictMode對(duì)象的setThreadPolicy()函數(shù)的參數(shù)。注意到setThreadPolicy()是一個(gè)靜態(tài)函數(shù),因此不需要實(shí)例化StrictMode對(duì)象。在內(nèi)部,setThreadPolicy()將對(duì)當(dāng)前線程應(yīng)用該策略。如果不指定檢測(cè)函數(shù),也可以用detectAll()來(lái)替代。penaltyLog()表示將警告輸出到LogCat,你也可以使用其他或增加新的懲罰(penalty)函數(shù),例如使用penaltyDeath()的話,一旦StrictMode消息被寫(xiě)到LogCat后應(yīng)用就會(huì)崩潰。
你不需要頻繁打開(kāi)嚴(yán)苛模式(StrictMode),你可以在主活動(dòng)的onCreate()函數(shù)中打開(kāi)它,你也可以在Application派生類的OnCreate()函數(shù)中設(shè)置嚴(yán)苛模式(StrictMode)。線程中運(yùn)行的任何代碼都可以設(shè)置嚴(yán)苛模式(StrictMode),但你的確只需要設(shè)置一次,一次就夠了。
類似于線程策略(ThreadPolicy),嚴(yán)苛模式(StrictMode)有虛擬機(jī)策略(VmPolicy)。虛擬機(jī)策略(VmPolicy)能檢查內(nèi)存泄漏,譬如,當(dāng)關(guān)閉一個(gè)SQLite對(duì)象前的完結(jié)操作,或其他任何類似可關(guān)閉對(duì)象在關(guān)閉前的完結(jié)操作。虛擬機(jī)策略(VmPolicy)由一個(gè)類似的Builder類創(chuàng)建,如列表2-10所示。和線程策略(ThreadPolicy)不同的是,虛擬機(jī)策略(VmPolicy)不能通過(guò)一個(gè)對(duì)話框提供警告。
列表2-10 設(shè)置嚴(yán)苛模式(StrictMode)的虛擬機(jī)策略
StrictMode.setVmPolicy(newStrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.penaltyLog()
.penaltyDeath()
.build());
因?yàn)樵O(shè)置發(fā)生在線程中,嚴(yán)苛模式(StrictMode)甚至能在從一個(gè)對(duì)象到另一個(gè)對(duì)象的控制流中找到違例事件。當(dāng)違例發(fā)生,你會(huì)驚奇地注意到代碼正運(yùn)行于主線程,而棧trace將幫助你發(fā)現(xiàn)它如何發(fā)生。于是你能單步調(diào)試解決問(wèn)題,或是將代碼移到它自己的后臺(tái)線程,或是就保持原來(lái)的處理方式。這都取決與你。當(dāng)然,你可能希望適時(shí)關(guān)閉嚴(yán)苛模式(StrictMode),當(dāng)你的程序作為產(chǎn)品發(fā)布時(shí),你可不希望它僅為了一個(gè)警告在你的用戶手里崩潰。
有兩個(gè)方法可以關(guān)閉嚴(yán)苛模式(StrictMode),最直接的就是移除相應(yīng)代碼,但這樣做不利于持續(xù)開(kāi)發(fā)的產(chǎn)品。你通常可以定義一個(gè)應(yīng)用級(jí)別布爾變量來(lái)測(cè)試是否需要調(diào)用嚴(yán)苛模式(StrictMode)代碼。在發(fā)布產(chǎn)品前將這個(gè)值定義為FALSE。更優(yōu)雅的方式是利用調(diào)試模式(debug mode)的特點(diǎn),在AndroidManifest.xml中定義這個(gè)布爾變量。字段的屬性之一是android:debuggable,其義自明。列表2-11給出了利用該特性的控釋方法。
列表2-11 僅在調(diào)試模式設(shè)置嚴(yán)苛模式(StrictMode)
//?Return?if?this?application?is?not?in?debug?mode
ApplicationInfo?appInfo?=?context.getApplicationInfo();
intappFlags?=?appInfo.flags;
if((appFlags?&?ApplicationInfo.FLAG_DEBUGGABLE)?!=0)?{
//?Do?StrictMode?setup?here
StrictMode.setVmPolicy(newStrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.penaltyLog()
.penaltyDeath()
.build());
}
使用Eclipse調(diào)試環(huán)境,ADT自動(dòng)為你設(shè)置debuggable屬性,使項(xiàng)目更易于管理。當(dāng)你在模擬器上或直接在設(shè)備上部署應(yīng)用,debuggable屬性為T(mén)RUE,當(dāng)你導(dǎo)出應(yīng)用建立一個(gè)產(chǎn)品版本,ADT將該屬性置為FALSE。注意,如果你另行設(shè)置了這個(gè)屬性值,ADT不會(huì)改變它。
嚴(yán)苛模式(StrictMode)很不錯(cuò),不過(guò)在Android 2.3之前的版本上該模式不工作。為了避免這個(gè)問(wèn)題,你要在StrictMode對(duì)象還不存在的時(shí)候就驗(yàn)證版本是否在Android2.3及以上。你能利用反射技術(shù)(reflection),當(dāng)嚴(yán)苛模式(StrictMode)函數(shù)有效時(shí)間接調(diào)用它,反之不去調(diào)用。方法很簡(jiǎn)單,你能按列表2-12中的代碼處理
列表2-12? 利用反射技術(shù)(reflection)調(diào)用嚴(yán)苛模式(StrictMode)
try{
Class?sMode?=?Class.forName("android.os.StrictMode");
Method?enableDefaults?=?sMode.getMethod("enableDefaults");
enableDefaults.invoke(null);
}
catch(Exception?e)?{
//?StrictMode?not?supported?on?this?device,?punt
Log.v("StrictMode","...?not?supported.?Skipping...");
}
當(dāng)嚴(yán)苛模式(StrictMode)不存在,將捕捉到ClassNotFoundException異常。enableDefault()是嚴(yán)苛模式(StrictMode)類的另一個(gè)函數(shù),它檢測(cè)所有違例并寫(xiě)入LogCat。因?yàn)檫@里調(diào)用的是靜態(tài)形式的enableDefault(),所以用null作為參數(shù)傳入。
某些時(shí)候你不希望報(bào)告所有違例。那在主線程之外的其他線程中設(shè)置嚴(yán)苛模式(StrictMode)很不錯(cuò)。譬如,你需要在正在監(jiān)視的線程中進(jìn)行磁盤(pán)讀取。此時(shí),你要么不去調(diào)用detectDiskReads(),要么在調(diào)用detectAll()之后跟一個(gè)permitDiskReads()。類似允許函數(shù)也適用于其他操作。但要是你要在Anroid2.3之前版本上做這些事,有辦法嗎?當(dāng)然有。
當(dāng)應(yīng)用中嚴(yán)苛模式(StrictMode)無(wú)效,如果你試圖訪問(wèn)它,將拋出一個(gè)VerifyError異常。如果你將嚴(yán)苛模式(StrictMode)封裝在一個(gè)類里,并捕捉這個(gè)錯(cuò)誤,當(dāng)嚴(yán)苛模式(StrictMode)無(wú)效時(shí),你能忽略它。列表2-13顯示一個(gè)簡(jiǎn)單的嚴(yán)苛模式(StrictMode)封裝類StrictModeWrapper。列表2-14顯示了如何在你的應(yīng)用中使用這個(gè)封裝類。
列表 2–13 在Anroid2.3之前版本建立嚴(yán)苛模式(StrictMode)封裝類
importandroid.content.Context;
importandroid.content.pm.ApplicationInfo;
importandroid.os.StrictMode;
publicclassStrictModeWrapper?{
publicstaticvoidinit(Context?context)?{
//?check?if?android:debuggable?is?set?to?true
intappFlags?=?context.getApplicationInfo().flags;
if((appFlags?&?ApplicationInfo.FLAG_DEBUGGABLE)?!=0)?{
StrictMode.setThreadPolicy(newStrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyLog()
.build());
StrictMode.setVmPolicy(newStrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.penaltyLog()
.penaltyDeath()
.build());
}
}
}
列表 2–14? 在Anroid2.3之前版本調(diào)用嚴(yán)苛模式(StrictMode)封裝類
try{
StrictModeWrapper.init(this);
}
catch(Throwable?throwable)?{
Log.v("StrictMode","...?is?not?available.?Punting...");
}
//如果考慮到關(guān)于版本兼容問(wèn)題,因?yàn)榘凑丈厦娴膶?xiě)法在2.3以下系統(tǒng)是沒(méi)有問(wèn)題的,但是在2.3以上的話,就會(huì)出錯(cuò),所以應(yīng)該采用以下方式來(lái)處理:
[java]view plaincopy
@SuppressLint("NewApi")
publicstaticvoidinit(Context?context)?{
//?check?if?android:debuggable?is?set?to?true
intappFlags?=?context.getApplicationInfo().flags;
if((appFlags?&?ApplicationInfo.FLAG_DEBUGGABLE)?!=0)?{
try{
//Android?2.3及以上調(diào)用嚴(yán)苛模式
Class?sMode?=?Class.forName("android.os.StrictMode");
Method?enableDefaults?=?sMode.getMethod("enableDefaults");
enableDefaults.invoke(null);
}catch(Exception?e)?{
//?StrictMode?not?supported?on?this?device,?punt
Log.v("StrictMode","...?not?supported.?Skipping...");
}
/*
*?StrictMode.setThreadPolicy(new?StrictMode.ThreadPolicy.Builder()
*?.detectDiskReads()?.detectDiskWrites()?.detectNetwork()
*?.penaltyLog()?.build());?StrictMode.setVmPolicy(new
*?StrictMode.VmPolicy.Builder()?.detectLeakedSqlLiteObjects()
*?.penaltyLog()?.penaltyDeath()?.build());
*/
}
}
http://blog.csdn.net/brokge/article/details/8543145