App優化 StrictMode 嚴格模式


StrictMode簡介

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

示例代碼  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();  
 }  

使用方法        

 如果不指定檢測函數,也可以用detectAll()來替代。penaltyLog()表示將警告輸出到LogCat,你也可以使用其他或增加新的懲罰(penalty)函數,例如使用penaltyDeath()的話,一旦StrictMode消息被寫到LogCat后應用就會崩潰。具體支持的監視方法見:StrictMode.ThreadPolicy.Builder 與 StrictMode.VmPolicy.Builder


在正式版本中,我們並不希望使用StrictMode來讓用戶的應用因為一個警告而崩潰,所以在應用正式發布時,需要移出這些監視。你可以通過刪除代碼來實現,不過這里提供一個更好的方式來解決這個問題,即使用AndroidMainifest文件中的debuggable屬性來實現,代碼如下所示:

android:debuggable="true"  

PS:可能在gradle中這么配置也行

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());   
}  


實例

 我們在測試代碼的主線程中去訪問網絡,這樣就一定會觸發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();
			}
		}
	}
}

運行代碼,並將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

這行Log中可以顯示出StrictMode提示的原因,通過這里的TraceLog我們就可以來找到優化的方法。

除了在Logcat中查看StrictMode的日志信息,如果你使用了penaltyDropbox()方法,那么你還可以通過如下所示的命令來調用DropBoxManager觀察StrictMode日志:

adb shell dumpsys dropbox data_app_strictmode --print

同時,如果使用了penaltyDialog()方法,在應用中還會彈出如下所示的提示框:


暫停監測

如果在程序運行中無法避免的會違反StrictMode中的一些定義好的策略,而我們又希望能夠暫時忽略這些策略的監視,我們可以使用permitXXXXX方法來暫停這些內容的監測,在做完需要忽略的監測之后,再啟用監測,代碼如下所示:
StrictMode.ThreadPolicy old = StrictMode.getThreadPolicy();  
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder(old)  
        .permitDiskWrites()  
        .build());  
//doSomethingWriteToDisk();  
StrictMode.setThreadPolicy(old);  

2017-10-20






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM