Thursday, February 02, 2012

Android最佳實踐之:StrictMode介紹


it168網站原創 作者:廖煜嶸 編輯:景保玉
【IT168技術】最新的Android平台中(Android 2.3起),新增加了一個新的類,叫StrictMode(android.os.StrictMode)。這個類可以用來幫助開發者改進他們編寫的應用,並且提供了各種的策略,這些策略能隨時檢查和報告開發者開發應用中存在的問題,比如可以監視那些本不應該在主線程中完成的工作或者其他的一些不規範和不好的代碼。
StrictMode有多種不同的策略,每一種策略又有不同的規則,當開發者違背某個規則時,每個策略都有不同的方法去顯示提醒用戶。在本文中,將舉例子說明如何使用在Android 中使用 StrictMode。
StrictMode的策略和規則
目前,有兩大類的策略可供使用,一類是關於常用的監控方面的,另外一類是關於VM虛擬機等方面的策略。常用的監控方面的策略有如下這些:
Disk Reads 磁盤讀
Disk Writes 磁盤寫
Network access 網絡訪問
Custom Slow Code 自定義的運行速度慢的代碼分析
前面三種的意思讀者應該很清楚,就是正如它們的名字所示,分別對磁盤的讀和寫,網絡訪問進行監控。而第四種的自定義慢代碼分析,是僅當訪問調用類的時後才觸發的,可以通過這種方法去監視運行緩慢的代碼。當在主線程中調用時,這些驗證規則就會起作用去檢查你的代碼。比如,當你的應用在下載或者解析大量的數據時,你可以觸發自定義運行速度慢代碼的查詢分析,作用很大。StrictMode可以用於捕捉發生在應用程序主線程中耗時的磁盤、網絡訪問或函數調用,可以幫助開發者使其改進程序,使主線程處理UI和動畫在磁盤讀寫和網絡操作時變得更平滑,避免主線程被阻塞的發生。
而VM方面的策略重點關注如下幾類:
內存洩露的Activity對象
內存洩露的SQLite對象
內存洩露的釋放的對象
其中,內存洩露的Activity對象和內存洩露的SQLite對象都比較好理解,而所謂對關閉對象的檢查,主要是去監那些本該釋放的對象,比如應該調用close()方法的對象。
當開發者違反某類規則時,每種策略都會有不同的方法令開發者知道當時的情況。相關的違反情況可以記錄在LogCat中或者存儲在DropBox中(android.os.DropBox)服務中。而常用監控類的策略還會在當違規情況發生時顯示相關的對話框和當時的上下文環境,所有的這些都為了能讓開發者盡快地瞭解程序的瑕疵,以提交程序的質量。下面分步講解如何使用stritctmode。


第一步 啟用strictmode
為了能在應用中啟用和配置StrictMode,開發者最好儘可能在應用程序的生命週期的早段使用,方法是調用StrictMode的方法setThreadPolicy。當使用常用監控類的時候,一個最好的調用時機,是在應用中入口和activities被調用前進行。比如在一個應用程序中,可以把代碼放在啟動Activity類的onCreate()方法中,下面是一個代碼示例,啟用了當前情況下的所有策略及規則,當程序中出現違背常用的規則時,將會顯示相關的提示信息窗口:
   StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() 
        .detectAll() 
        .penaltyLog() 
        .penaltyDialog() 
////打印logcat,當然也可以定位到dropbox,通過文件保存相應的log
        .build()); 
StrictMode.setVmPolicy(
new StrictMode.VmPolicy.Builder().detectAll() 
        .penaltyLog() 
        .build());
當然,以上代碼只應在未發佈上線的測試版本的應用中運行以方便監視相關的運行情況,當在生產版本上時不應該啟用strictmode。因此,最佳的代碼實踐應該為如下的樣子:
   public void onCreate() {  
    
if (DEVELOPER_MODE) {  
        StrictMode.setThreadPolicy(
new StrictMode.ThreadPolicy.Builder()  
                .detectDiskReads()  
                .detectDiskWrites()  
                .detectNetwork()  
                .penaltyLog()  
                .build());  
    }  
    super.onCreate();  
}  

第二步 運行strictmode
當應用啟用了strictmode模式時,其實跟普通的應用沒什麼兩樣,在測試和運行時,跟平時運行普通應用程序一樣就可以了。當啟用了Strictmode模式時,會監視所有的程序運行情況,當發現出現重大問題或違背策略規則時,會提示用戶。下面是當運行啟用了strictmode模式的應用時,當發現違背規則時,顯示給用戶的信息,細心觀察下跟普通的出錯信息有什麼不同吧。
09-04 16:15:34.592: DEBUG/StrictMode(15883): StrictMode policy violation; ~duration=319 ms: android.os.StrictMode$StrictModeDiskWriteViolation: policy=31 violation=1
09-04 16:15:34.592: DEBUG/StrictMode(15883):     at android.os.StrictMode$AndroidBlockGuardPolicy.onWriteToDisk(StrictMode.java:1041)
09-04 16:15:34.592: DEBUG/StrictMode(15883):     at android.database.sqlite.SQLiteStatement.acquireAndLock(SQLiteStatement.java:219)09-04 16:15:34.592: DEBUG/StrictMode(15883):     at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:8309-04 16:15:34.592: DEBUG/StrictMode(15883):     at android.database.sqlite.SQLiteDatabase.updateWithOnConflict(SQLiteDatabase.java:182909-04 16:15:34.592: DEBUG/StrictMode(15883):     at android.database.sqlite.SQLiteDatabase.update(SQLiteDatabase.java:178009-04 16:15:34.592: DEBUG/StrictMode(15883):     at com.mamlambo.tutorial.tutlist.data.TutListProvider.update(TutListProvider.java:18809-04 16:15:34.592: DEBUG/StrictMode(15883):     at android.content.ContentProvider$Transport.update(ContentProvider.java:23309-04 16:15:34.592: DEBUG/StrictMode(15883):     at android.content.ContentResolver.update(ContentResolver.java:84709-04 16:15:34.592: DEBUG/StrictMode(15883):     at com.mamlambo.tutorial.tutlist.data.TutListProvider.markItemRead(TutListProvider.java:22909-04 16:15:34.592: DEBUG/StrictMode(15883):     at com.mamlambo.tutorial.tutlist.TutListFragment.onListItemClick(TutListFragment.java:9909-04 16:15:34.592: DEBUG/StrictMode(15883):     at android.support.v4.app.ListFragment$2.onItemClick(ListFragment.java:5309-04 16:15:34.592: DEBUG/StrictMode(15883):     at android.widget.AdapterView.performItemClick(AdapterView.java:28209-04 16:15:34.592: DEBUG/StrictMode(15883):     at android.widget.AbsListView.performItemClick(AbsListView.java:103709-04 16:15:34.592: DEBUG/StrictMode(15883):     at android.widget.AbsListView$PerformClick.run(AbsListView.java:244909-04 16:15:34.592: DEBUG/StrictMode(15883):     at android.widget.AbsListView$1.run(AbsListView.java:307309-04 16:15:34.592: DEBUG/StrictMode(15883):     at android.os.Handler.handleCallback(Handler.java:58709-04 16:15:34.592: DEBUG/StrictMode(15883):     at android.os.Handler.dispatchMessage(Handler.java:9209-04 16:15:34.592: DEBUG/StrictMode(15883):     at android.os.Looper.loop(Looper.java:13209-04 16:15:34.592: DEBUG/StrictMode(15883):     at android.app.ActivityThread.main(ActivityThread.java:412309-04 16:15:34.592: DEBUG/StrictMode(15883):     at java.lang.reflect.Method.invokeNative(Native Method) 09-04 16:15:34.592: DEBUG/StrictMode(15883):     at java.lang.reflect.Method.invoke(Method.java:49109-04 16:15:34.592: DEBUG/StrictMode(15883):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:84109-04 16:15:34.592: DEBUG/StrictMode(15883):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599
09-04 16:15:34.592: DEBUG/StrictMode(15883):     at dalvik.system.NativeStart.main(Native Method
並且會出現如下的提示窗口,提示用戶:
Android最佳實踐之:StrictMode介紹
 忽略某些規則
應該說大部分由StrictMode產生的規則警示都應去遵守,但有時也不是所有產生的信息都表明你的程序有錯誤。比如,在應用程序的主線程中去快速讀寫磁盤其實不會對應用的性能產生太大的影響,又或者你在調試程序階段有一些調試的代碼違反了設定的規則,這些都可以忽略掉這些規則。
忽略規則有兩種方法,一種是單純在代碼中把Strictmode的代碼註釋掉,另外一種比較好的方法是,在需要忽略的時候和地方,增加相應的代碼去讓系統停止使用這些規則去檢查,等開發者認為有必要檢查時,再重新應用這些規則,比如:
StrictMode.ThreadPolicy old = StrictMode.getThreadPolicy();
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder(old)
.permitDiskWrites()
.build());
doCorrectStuffThatWritesToDisk();
StrictMode.setThreadPolicy(old);
這裡首先用old來保存了當前的策略規則,然後doCorrectStuffThatWritesToDisk();
這裡,執行了一些向磁盤快速讀寫的操作,最後又重新啟用了這些規則。
 小結
StrictMode是一個十分有用的類,它可以很方便地應用於檢查Android應用程序的性能和存在的問題。當開啟這個模式後,開發者能很好地檢查應用中存在的潛在問題,更多的請參考Android文檔中的相關API說明。

No comments: