Android中的StrictMode

Android 2.3提供一個稱爲嚴苛模式(StrictMode)的調試特性,Google稱該特性已經使數百個Android上的Google應用程序受益。那它都做什麼呢?它將報告與線程及虛擬機相關的策略違例。一旦檢測到策略違例(policy violation),你將獲得警告,其包含了一個棧trace顯示你的應用在何處發生違例。你可以強制用警告代替崩潰(crash),也可以僅將警告計入日誌,讓你的應用繼續執行。策略的細節尚難確定,可以期待隨Android的成熟Google將增加更多策略。

    目前有2種策略可用,第一個和線程相關,它主要針對主線程(或UI線程)。由於在主線程中讀寫磁盤和進行網絡訪問都不是好的做法,Google已經在磁盤和網絡代碼中添加了嚴苛模式(StrictMode)鉤子(hook)。如果你對某個線程打開嚴苛模式(StrictMode),當那個線程進行磁盤和網絡訪問,你將獲得警告。你可以選擇警告方式。一些違例包含用戶慢速調用(custom slow calls 這麼翻譯行嗎?),磁盤讀寫,網絡訪問。你能選擇將警告寫入LogCat,顯示一個對話框,閃下屏幕,寫入DropBox日誌文件,或讓應用崩潰。最通常的做法是寫入LogCat或讓應用崩潰。


 

寫程序時,你應該始終假定下列兩種情況:

網絡很慢(你正在試圖連接的服務器甚至可能沒有響應);

文件系統的訪問速度很慢。

結論就是,不應該在主線程內進行網絡操作或訪問文件系統,因爲緩慢的操作會拖累系統的響應能力。雖然在開發環境中,你可能永遠不會遇到任何網絡問題或任何文件系統的性能問題,但用戶可能不像你那麼幸運。

注意 SD卡並不都具有相同“速度”,如果應用在很大程度上依賴外部存儲設備的性能,那麼你應該確保在來自不同製造商的各種SD卡上測試過你的應用。

Android有實用工具來幫助應用檢測這類缺陷。它提供的StrictMode是檢測不良行爲的良好工具。通常情況下,在應用啓動時,即當onCreate()被調用時,啓用StrictMode,如代碼清單1-15所示。

在應用中啓用StrictMode

[java] view plaincopy
  1. public class MyApplication extends Application {  
  2.     @Override  
  3.     public void onCreate () {  
  4.         super.onCreate();  
  5.   
  6.         StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()  
  7.         .detectCustomSlowCalls()// API等級11,使用StrictMode.noteSlowCode  
  8.         .detectDiskReads()  
  9.         .detectDiskWrites()  
  10.         .detectNetwork()  
  11.         .penaltyLog()  
  12.         .penaltyFlashScreen()// API等級11  
  13.         .build());  
  14.   
  15.          // 其實和性能無關,但如果使用StrictMode,最好也定義VM策略  
  16.          StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()  
  17.          .detectLeakedSqlLiteObjects()  
  18.          .detectLeakedClosableObjects()// API等級11  
  19.          .setClassInstanceLimit(Class.forName("com.apress.proandroid.SomeClass"100)// API等級11  
  20.          .penaltyLog()  
  21.          .build());  
  22.       }  
  23. }  


StrictMode是Android 2.3引入的,在Android 3.0中加入了更多的功能,所以應該確保選擇了正確的Android版本,讓代碼跑在適當的Android平臺上,如代碼清單1-12所示。

Android 3.0中引入的需要特別留意的方法包括detectCustomSlowCall()和noteSlowCall(),它們都是用來檢測應用中執行緩慢的代碼或潛在緩慢的代碼。代碼清單1-16說明了如何將代碼標記爲潛在緩慢的代碼。

 

代碼清單1-16 標記潛在緩慢的代碼

[java] view plaincopy
  1. public class Fibonacci {  
  2.     public static BigInteger computeRecursivelyWithCache(int n) {  
  3.        StrictMode.noteSlowCall("computeRecursivelyWithCache");// 消息可以帶任何信息  
  4.          SparseArray cache = new SparseArray();  
  5.          return computeRecursivelyWithCache(n, cache);  
  6.      }  
  7.      ...  
  8. }  

 

 

[java] view plaincopy
  1.   
[java] view plaincopy
  1. public class Fibonacci {  
  2.     public static BigInteger computeRecursivelyWithCache(int n) {  
  3.        StrictMode.noteSlowCall("computeRecursivelyWithCache");// 消息可以帶任何信息  
  4.          SparseArray cache = new SparseArray();  
  5.          return computeRecursivelyWithCache(n, cache);  
  6.      }  
  7.      ...  
  8. }  

從主線程調用computeRecursivelyWithCache執行時間過長,如果StrictMode Thread 策略配置爲檢測緩慢調用時,會出現如下日誌:

[java] view plaincopy
  1. StrictMode policy violation; ~duration=21121 ms:  
  2. android.os.StrictMode$StrictModeCustomViolation: policy=31 violation=8 msg=computeRecursivelyWithCache  

StrictMode policy violation; ~duration=21121 ms:
android.os.StrictMode$StrictModeCustomViolation: policy=31 violation=8 msg=computeRecursivelyWithCache

 

Android提供了一些輔助方法,可以在主線程裏進行臨時磁盤讀寫,如代碼

[java] view plaincopy
  1. StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();  

修改線程策略,臨時允許磁盤讀取

[java] view plaincopy
  1. StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();  
  2.  // 從磁盤讀取數據  
  3.  StrictMode.setThreadPolicy(oldPolicy);  


 

目前沒有臨時允許網絡訪問的方法,但實在沒有理由在主線程中允許這種訪問,即使是暫時的,也沒有合適的方式知道訪問是否很快。有人可能會說,也沒有合理的方式知道磁盤訪問將是否是快速的,但那是另一場爭論。

注意 只在開發階段啓用StrictMode,發佈應用時,記得要禁用它。如果你使用detectAll()方法去建立策略總是可行的,那將來更可行,未來的Android版本會檢測出更多的不良行爲。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章