StrictMode簡介
StrictMode最常用來捕捉應用程序的主線程,它將報告與線程及虛擬機相關的策略違例。一旦檢測到策略違例policy violation,你將獲得警告,其包含了一個棧trace顯示你的應用在何處發生違例。除了主線程,我們還可以在Handler,AsyncTask,AsyncQueryHandler,IntentService等API中使用StrictMode。

檢查策略
StrictMode的線程策略主要用於檢測磁盤IO和網絡訪問,而虛擬機策略主要用於檢測內存泄漏現象。Android已經在磁盤IO訪問和網絡訪問的代碼中加入了StrictMode。當監視的線程發生策略的違例時,就可以獲得警告,例如寫入LogCat,顯示一個對話框,閃下屏幕,寫入DropBox日志文件,或讓應用崩潰。最通常的做法是寫入LogCat或讓應用崩潰。下面的代碼展示了如何使用StrictMode的檢查策略:
public void onCreate() {
if (DEVELOPER_MODE) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() //線程策略
.detectDiskReads() //detect [dɪˈtɛkt] vt.查明,發現; 洞察; 偵察,偵查;
.detectDiskWrites()
.detectNetwork()
// or .detectAll() for all detectable problems
.penaltyDialog() //penalty [ˈpɛnəlti] n.刑罰; 懲罰; 害處
.penaltyLog()
.penaltyDropBox() //DropBox下拉框
.build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() //虛擬機策略
.detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects()
.penaltyLog()
.penaltyDeath()
.build());
}
super.onCreate();
}
public void onCreate() {
if (DEVELOPER_MODE) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() //線程策略
.detectDiskReads() //detect [dɪˈtɛkt] vt.查明,發現; 洞察; 偵察,偵查;
.detectDiskWrites()
.detectNetwork()
// or .detectAll() for all detectable problems
.penaltyDialog() //penalty [ˈpɛnəlti] n.刑罰; 懲罰; 害處
.penaltyLog()
.penaltyDropBox() //DropBox下拉框
.build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() //虛擬機策略
.detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects()
.penaltyLog()
.penaltyDeath()
.build());
}
super.onCreate();
}
使用方法
如果不指定檢測函數,也可以用detectAll()來替代。penaltyLog()表示將警告輸出到LogCat,你也可以使用其他或增加新的懲罰(penalty)函數,例如使用penaltyDeath()的話,一旦StrictMode消息被寫到LogCat后應用就會崩潰。具體支持的監視方法見:StrictMode.ThreadPolicy.Builder 與 StrictMode.VmPolicy.Builder。
在正式版本中,我們並不希望使用StrictMode來讓用戶的應用因為一個警告而崩潰,所以在應用正式發布時,需要移出這些監視。你可以通過刪除代碼來實現,不過這里提供一個更好的方式來解決這個問題,即使用AndroidMainifest文件中的debuggable屬性來實現,代碼如下所示:
android:debuggable="true"
android:debuggable="true"
PS:可能在gradle中這么配置也行
android {
buildTypes {
debug {
debuggable true
}
}
}
android {
buildTypes {
debug {
debuggable true
}
}
}
在代碼中,使用方法如下所示:
// Return if this application is not in debug mode
if ((context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
// Do StrictMode setup here
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.penaltyLog()
.penaltyDeath()
.build());
}
// Return if this application is not in debug mode
if ((context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
// Do StrictMode setup here
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.penaltyLog()
.penaltyDeath()
.build());
}
實例
我們在測試代碼的主線程中去訪問網絡,這樣就一定會觸發StrictMode的線程監測,代碼如下所示:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyDialog()
.penaltyLog()
.penaltyDropBox()
.build());
super.onCreate(savedInstanceState);
TextView mTextView = new TextView(this);
setContentView(mTextView);
InputStream inputStream = null;
try {
HttpResponse httpResponse = new DefaultHttpClient().execute(new HttpGet("http://www.baidu.com"));
HttpEntity httpEntity = httpResponse.getEntity();
if (httpResponse.getStatusLine().getStatusCode() == 200) {
inputStream = httpEntity.getContent();
mTextView.setText(new BufferedReader(new InputStreamReader(inputStream)).readLine());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (inputStream != null) inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyDialog()
.penaltyLog()
.penaltyDropBox()
.build());
super.onCreate(savedInstanceState);
TextView mTextView = new TextView(this);
setContentView(mTextView);
InputStream inputStream = null;
try {
HttpResponse httpResponse = new DefaultHttpClient().execute(new HttpGet("http://www.baidu.com"));
HttpEntity httpEntity = httpResponse.getEntity();
if (httpResponse.getStatusLine().getStatusCode() == 200) {
inputStream = httpEntity.getContent();
mTextView.setText(new BufferedReader(new InputStreamReader(inputStream)).readLine());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (inputStream != null) inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
運行代碼,並將Log信息保存到本地,在Log中,我們可以搜索D/StrictMode關鍵字,如下所示:
D/StrictMode: StrictMode policy violation; ~duration=5131 ms: android.os.StrictMode$StrictModeDiskReadViolation: policy=183 violation=2
at android.os.StrictMode$AndroidBlockGuardPolicy.onReadFromDisk(StrictMode.java:1157)
at libcore.io.BlockGuardOs.open(BlockGuardOs.java:182)
at libcore.io.IoBridge.open(IoBridge.java:480)
at java.io.FileInputStream.<init>(FileInputStream.java:76)
at java.io.FileInputStream.<init>(FileInputStream.java:103)
at android.content.res.HwResources.readDefaultConfig(HwResources.java:1172)
at android.content.res.HwResources.loadDrawable(HwResources.java:574)
at android.content.res.Resources.getDrawable(Resources.java:809)
at android.content.Context.getDrawable(Context.java:403)
at com.android.internal.widget.ToolbarWidgetWrapper.setIcon(ToolbarWidgetWrapper.java:321)
at com.android.internal.widget.ActionBarOverlayLayout.setIcon(ActionBarOverlayLayout.java:741)
at com.android.internal.policy.impl.PhoneWindow.setDefaultIcon(PhoneWindow.java:1661)
at android.app.Activity.initWindowDecorActionBar(Activity.java:2174)
at android.app.Activity.setContentView(Activity.java:2189)
at com.imooc.strictmodetest.MainActivity.onCreate(MainActivity.java:36)
at android.app.Activity.performCreate(Activity.java:6102)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2403)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2512)
at android.app.ActivityThread.access$1200(ActivityThread.java:165)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1373)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5593)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:967)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:762)
D/StrictMode: StrictMode policy violation; ~duration=5131 ms: android.os.StrictMode$StrictModeDiskReadViolation: policy=183 violation=2
at android.os.StrictMode$AndroidBlockGuardPolicy.onReadFromDisk(StrictMode.java:1157)
at libcore.io.BlockGuardOs.open(BlockGuardOs.java:182)
at libcore.io.IoBridge.open(IoBridge.java:480)
at java.io.FileInputStream.<init>(FileInputStream.java:76)
at java.io.FileInputStream.<init>(FileInputStream.java:103)
at android.content.res.HwResources.readDefaultConfig(HwResources.java:1172)
at android.content.res.HwResources.loadDrawable(HwResources.java:574)
at android.content.res.Resources.getDrawable(Resources.java:809)
at android.content.Context.getDrawable(Context.java:403)
at com.android.internal.widget.ToolbarWidgetWrapper.setIcon(ToolbarWidgetWrapper.java:321)
at com.android.internal.widget.ActionBarOverlayLayout.setIcon(ActionBarOverlayLayout.java:741)
at com.android.internal.policy.impl.PhoneWindow.setDefaultIcon(PhoneWindow.java:1661)
at android.app.Activity.initWindowDecorActionBar(Activity.java:2174)
at android.app.Activity.setContentView(Activity.java:2189)
at com.imooc.strictmodetest.MainActivity.onCreate(MainActivity.java:36)
at android.app.Activity.performCreate(Activity.java:6102)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2403)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2512)
at android.app.ActivityThread.access$1200(ActivityThread.java:165)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1373)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5593)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:967)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:762)
主要看第一行
D/StrictMode: StrictMode policy violation; ~duration=5131 ms: android.os.StrictMode$StrictModeDiskReadViolation: policy=183 violation=2
D/StrictMode: StrictMode policy violation; ~duration=5131 ms: android.os.StrictMode$StrictModeDiskReadViolation: policy=183 violation=2
這行Log中可以顯示出StrictMode提示的原因,通過這里的TraceLog我們就可以來找到優化的方法。
除了在Logcat中查看StrictMode的日志信息,如果你使用了penaltyDropbox()方法,那么你還可以通過如下所示的命令來調用DropBoxManager觀察StrictMode日志:
adb shell dumpsys dropbox data_app_strictmode --print
adb shell dumpsys dropbox data_app_strictmode --print
同時,如果使用了penaltyDialog()方法,在應用中還會彈出如下所示的提示框:

暫停監測
StrictMode.ThreadPolicy old = StrictMode.getThreadPolicy();
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder(old)
.permitDiskWrites()
.build());
//doSomethingWriteToDisk();
StrictMode.setThreadPolicy(old);
x
StrictMode.ThreadPolicy old = StrictMode.getThreadPolicy();
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder(old)
.permitDiskWrites()
.build());
//doSomethingWriteToDisk();
StrictMode.setThreadPolicy(old);
2017-10-20