Android之StrictMode

lvxiangan發表於2018-12-09

StrictMode簡介


StrictMode(android.os.StrictMode) 是一個自Android 2.3版(API 9。Gingerbread,薑餅)引入的類。

StrictMode是Strict和Mode的合併,在英語中,strict表示“嚴格的”,mode表示“模式”,因此,StrictMode就是“嚴格的模式”,或叫“嚴苛模式”。

StrictMode,嚴苛模式。在啟動StrictMode的情況下,程式必須嚴格遵守某種“要求”幹事,否則的話就會得到“懲罰”。如果程式在執行中沒有被“懲罰”,說明程式優化的比較好,否則程式要進行進一步優化。
“要求”分兩種:ThreadPolicyVmPolicy,ThreadPolicy是執行緒相關的要求,VmPolicy是虛擬機器相關的要求。

  • 執行緒策略檢測的內容有:
    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

相關文章