Android之StrictMode
StrictMode簡介
StrictMode(android.os.StrictMode) 是一個自Android 2.3版(API 9。Gingerbread,薑餅)引入的類。
StrictMode是Strict和Mode的合併,在英語中,strict表示“嚴格的”,mode表示“模式”,因此,StrictMode就是“嚴格的模式”,或叫“嚴苛模式”。
StrictMode,嚴苛模式。在啟動StrictMode的情況下,程式必須嚴格遵守某種“要求”幹事,否則的話就會得到“懲罰”。如果程式在執行中沒有被“懲罰”,說明程式優化的比較好,否則程式要進行進一步優化。
“要求”分兩種:
- 執行緒策略檢測的內容有:
1、自定義的耗時呼叫 使用detectCustomSlowCalls()開啟
2、磁碟讀取操作 使用detectDiskReads()開啟
3、磁碟寫入操作 使用detectDiskWrites()開啟
4、網路操作 使用detectNetwork()開啟 - VmPolicy虛擬機器策略檢測
-
1、Activity洩露 使用detectActivityLeaks()開啟
2、未關閉的Closable物件洩露 使用detectLeakedClosableObjects()開啟
3、洩露的Sqlite物件 使用detectLeakedSqlLiteObjects()開啟
4、檢測例項數量 使用setClassInstanceLimit()開啟
-
注意事項
- 只在開發階段啟用StrictMode,釋出應用或者release版本一定要禁用它。
- 嚴格模式無法監控JNI中的磁碟IO和網路請求。
- 應用中並非需要解決全部的違例情況,比如有些IO操作必須在主執行緒中進行。
策略型別
目前,有兩種型別的策略:
- Thread Policy : 執行緒策略應用到特定的執行緒。
- VM Policy : VM是Virtual Machine的縮寫,表示“虛擬機器”,不要搞錯以為是Virtual Memory(虛擬記憶體)。應用於虛擬機器程序中的所有執行緒。
ThreadPolicy.Builder中的一些方法:
- detectAll() : 偵測一切潛在違規
- detectCustomSlowCalls() : 偵測自定義的耗時操作
- detectDiskReads() : 偵測磁碟讀
- detectDiskWrites() : 偵測磁碟寫
- detectNetwork() : 偵測網路操作
- permitAll() : 禁用所有偵測
- permitDiskReads() : 允許磁碟讀
VmPolicy.Builder中的一些方法 :
- detectAll() : 偵測一切潛在違規
- detectActivityLeaks() : 偵測Activity(活動)洩露
- detectLeakedClosableObjects() : 當顯式中止方法呼叫之後,假如可被Closeable類或其他的物件沒有被關閉。
處罰
Penalty是英語“處罰”的意思,所以凡是以penalty開頭的方法都表示違規時要做出什麼反應。
對於每個策略,我們可以指定多個處罰形式,而處罰也是從最不嚴重的到最嚴重(從列印日誌到直接crash(崩潰))依次執行。
暫時還沒有機制能使監測到的違規與特定的處罰對應。
- penaltyDeath() : 違規時,直接使應用崩潰。
- penaltyDialog() : 違規時,向開發者顯示一個惱人的Dialog對話方塊。
- penaltyLog() : 違規時,將違規資訊寫入系統日誌。
使用
StrictMode使用起來非常簡單。
設定策略
你可以在你的Application(應用)或者應用中的Activity的onCreate()方法中設定啟用StrictMode的策略。不過為了更全面的監測,最好就放在Application的onCreate()方法中,一勞永逸。
設定StrictMode可以通過setVmPolicy(StrictMode.VmPolicy)或setThreadPolicy(StrictMode.ThreadPolicy)。
setVmPolicy(StrictMode.VmPolicy)或setThreadPolicy(StrictMode.ThreadPolicy)方法的引數是用VmPolicy.Builder或ThreadPolicy.Builder來構建的。
舉例:
@Override
public void onCreate() {
super.onCreate();
// 分別為MainThread和VM設定Strict Mode
if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.detectResourceMismatches()
.detectCustomSlowCalls()
.penaltyDeath()
.build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects()
.detectLeakedRegistrationObjects()
.detectActivityLeaks()
.penaltyDeath()
.build());
}
}
擴充StrictMode
1.用getThreadPolicy() 或getVmPolicy()獲得當前策略。
2.用setThreadPolicy() or setVmPolicy()來擴充它。
舉例:
StrictMode.ThreadPolicy oldThreadPolicy = StrictMode.getThreadPolicy();
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder(oldThreadPolicy)
.permitDiskWrites() // 在原有策略的規則基礎上,不監測讀寫磁碟
.build());
StrictMode.VmPolicy oldVmPolicy = StrictMode.getVmPolicy();
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder(oldVmPolicy)
.detectFileUriExposure() // 在原有策略的規則基礎上,監測檔案URI暴露
.build());
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)
可以看到,在Logcat中總會有StrictMode開頭的Log。因此,我們可以這樣查詢所有StrictMode的日誌:
adb logcat | grep StrictMode
測試例項
寫入外部儲存
public void writeToExternalStorage() {
File externalStorage = Environment.getExternalStorageDirectory();
File destFile = new File(externalStorage, "dest.txt");
try {
OutputStream output = new FileOutputStream(destFile, true);
output.write("coderunity.com".getBytes());
output.flush();
output.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Activity洩露
下面的程式碼,如果我們進入、退出多次LeakyActivity, 則會觸發
StrictMode.ThreadPolicy.Builder().detectActivityLeaks() :
public class MyApplication extends Application {
public static final boolean IS_DEBUG = true;
public static ArrayList<Activity> sLeakyActivities = new ArrayList<Activity>();
}
public class LeakyActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyApplication.sLeakyActivities.add(this);
}
}
在設定中啟用StrictMode
我們也可以在Android裝置的設定(Settings)中啟用StrictMode:
Settings(設定) -> Developer options(開發者選項),然後開啟它。開啟之後,一旦應用在主執行緒中執行耗時操作,螢幕就會閃爍。
轉自:https://www.jianshu.com/p/113b9c54b5d1