国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

Android嚴苛模式StrictMode使用詳解

2019-10-22 18:17:15
字體:
供稿:網(wǎng)友

StrictMode類是Android 2.3 (API 9)引入的一個工具類,可以用來幫助開發(fā)者發(fā)現(xiàn)代碼中的一些不規(guī)范的問題,以達到提升應(yīng)用響應(yīng)能力的目的。舉個例子來說,如果開發(fā)者在UI線程中進行了網(wǎng)絡(luò)操作或者文件系統(tǒng)的操作,而這些緩慢的操作會嚴重影響應(yīng)用的響應(yīng)能力,甚至出現(xiàn)ANR對話框。為了在開發(fā)中發(fā)現(xiàn)這些容易忽略的問題,我們使用StrictMode,系統(tǒng)檢測出主線程違例的情況并做出相應(yīng)的反應(yīng),最終幫助開發(fā)者優(yōu)化和改善代碼邏輯。

       官網(wǎng)文檔:http://developer.android.com/reference/android/os/StrictMode.html

StrictMode具體能檢測什么

嚴苛模式主要檢測兩大問題,一個是線程策略,即TreadPolicy,另一個是VM策略,即VmPolicy。

ThreadPolicy線程策略檢測

  • 線程策略檢測的內(nèi)容有
  • 自定義的耗時調(diào)用 使用detectCustomSlowCalls()開啟
  • 磁盤讀取操作 使用detectDiskReads()開啟
  • 磁盤寫入操作 使用detectDiskWrites()開啟
  • 網(wǎng)絡(luò)操作 使用detectNetwork()開啟

VmPolicy虛擬機策略檢測

  • Activity泄露 使用detectActivityLeaks()開啟
  • 未關(guān)閉的Closable對象泄露 使用detectLeakedClosableObjects()開啟
  • 泄露的Sqlite對象 使用detectLeakedSqlLiteObjects()開啟
  • 檢測實例數(shù)量 使用setClassInstanceLimit()開啟

工作原理

       其實StrictMode實現(xiàn)原理也比較簡單,以IO操作為例,主要是通過在open,read,write,close時進行監(jiān)控。libcore.io.BlockGuardOs文件就是監(jiān)控的地方。以open為例,如下進行監(jiān)控。

@Overridepublic FileDescriptor open(String path, int flags, int mode) throws ErrnoException { BlockGuard.getThreadPolicy().onReadFromDisk(); if ((mode & O_ACCMODE) != O_RDONLY) {  BlockGuard.getThreadPolicy().onWriteToDisk(); } return os.open(path, flags, mode);}

其中onReadFromDisk()方法的實現(xiàn),代碼位于StrictMode.java中。

public void onReadFromDisk() { if ((mPolicyMask & DETECT_DISK_READ) == 0) {  return; } if (tooManyViolationsThisLoop()) {  return; } BlockGuard.BlockGuardPolicyException e = new StrictModeDiskReadViolation(mPolicyMask); e.fillInStackTrace(); startHandlingViolationException(e);}

常見用法

       嚴格模式的開啟可以放在Application或者Activity以及其他組件的onCreate方法。為了更好地分析應(yīng)用中的問題,建議放在Application的onCreate方法中。 

       其中,我們只需要在app的開發(fā)版本下使用 StrictMode,線上版本避免使用 StrictMode,這里定義了一個布爾值變量DEV_MODE來進行控制。

private boolean DEV_MODE = true; public void onCreate() {  if (DEV_MODE) {   StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()     .detectCustomSlowCalls() //API等級11,使用StrictMode.noteSlowCode     .detectDiskReads()     .detectDiskWrites()     .detectNetwork() // or .detectAll() for all detectable problems     .penaltyDialog() //彈出違規(guī)提示對話框     .penaltyLog() //在Logcat 中打印違規(guī)異常信息     .penaltyFlashScreen() //API等級11     .build());   StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()     .detectLeakedSqlLiteObjects()     .detectLeakedClosableObjects() //API等級11     .penaltyLog()     .penaltyDeath()     .build());  }  super.onCreate(); }

       其中Android3.0引入的方法包括detectCustomSlowCalls()和noteSlowCode(),它們都是用來檢測應(yīng)用中執(zhí)行緩慢代碼的或者潛在的緩慢代碼。

查看報告結(jié)果

       嚴格模式有很多種報告違例的形式,但是想要分析具體違例情況,還是需要查看日志,終端下過濾StrictMode就能得到違例的具體stacktrace信息。

adb logcat | grep StrictMode

嚴苛模式,android,strictmode

當然也可以選擇彈窗形式來簡明提醒開發(fā)者

嚴苛模式,android,strictmode

彈窗警告

ThreadPolicy 詳解

StrictMode.ThreadPolicy.Builder 主要方法如下

detectNetwork() 用于檢查UI線程中是否有網(wǎng)絡(luò)請求操作

檢測UI線程中網(wǎng)絡(luò)請求案例:

public class MainActivity extends AppCompatActivity implements View.OnClickListener { Button btnTest; @Override protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_main);  StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()    .detectNetwork()    .penaltyLog()    .build());  btnTest = (Button) findViewById(R.id.btn_test);  btnTest.setOnClickListener(this); } @Override public void onClick(View v) {  int id = v.getId();  switch (id) {   case R.id.btn_test:    postNetwork();   break;  } } /**  * 網(wǎng)絡(luò)連接的操作  */ private void postNetwork() {  try {   URL url = new URL("http://www.wooyun.org");   HttpURLConnection conn = (HttpURLConnection) url.openConnection();   conn.connect();   BufferedReader reader = new BufferedReader(new InputStreamReader(     conn.getInputStream()));   String lines = null;   StringBuffer sb = new StringBuffer();   while ((lines = reader.readLine()) != null) {    sb.append(lines);   }  } catch (Exception e) {   e.printStackTrace();  } }}

運行后,觸發(fā)的警告如下

嚴苛模式,android,strictmode

detectDiskReads() 和 detectDiskWrites() 是磁盤讀寫檢查

磁盤讀寫檢查案例:

public class MainActivity extends AppCompatActivity implements View.OnClickListener { Button btnTest; @Override protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_main);  StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()    .detectDiskWrites()    .detectDiskReads()    .penaltyLog()    .build());  btnTest = (Button) findViewById(R.id.btn_test);  btnTest.setOnClickListener(this); } @Override public void onClick(View v) {  int id = v.getId();  switch (id) {   case R.id.btn_test:    writeToExternalStorage();    break;  } } /**  * 文件系統(tǒng)的操作  */ public void writeToExternalStorage() {  File externalStorage = Environment.getExternalStorageDirectory();  File mbFile = new File(externalStorage, "castiel.txt");  try {   OutputStream output = new FileOutputStream(mbFile, true);   output.write("www.wooyun.org".getBytes());   output.flush();   output.close();  } catch (FileNotFoundException e) {   e.printStackTrace();  } catch (IOException e) {   e.printStackTrace();  } }}

運行后,觸發(fā)的警告如下

嚴苛模式,android,strictmode

noteSlowCall針對執(zhí)行比較耗時的檢查

       StrictMode從 API 11開始允許開發(fā)者自定義一些耗時調(diào)用違例,這種自定義適用于自定義的任務(wù)執(zhí)行類中,比如我們有一個進行任務(wù)處理的類,為TaskExecutor。

public class TaskExecutor { public void execute(Runnable task) {  task.run(); }}

       先需要跟蹤每個任務(wù)的耗時情況,如果大于500毫秒需要提示給開發(fā)者,noteSlowCall就可以實現(xiàn)這個功能,如下修改代碼

public class TaskExecutor { private static long SLOW_CALL_THRESHOLD = 500; public void executeTask(Runnable task) {  long startTime = SystemClock.uptimeMillis();  task.run();  long cost = SystemClock.uptimeMillis() - startTime;  if (cost > SLOW_CALL_THRESHOLD) {   StrictMode.noteSlowCall("slowCall cost=" + cost);  } }}

執(zhí)行一個耗時2000毫秒的任務(wù)

TaskExecutor executor = new TaskExecutor();executor.executeTask(new Runnable() { @Override public void run() {  try {   Thread.sleep(2000);  } catch (InterruptedException e) {   e.printStackTrace();  } }});

       得到的違例日志,注意其中~duration=20 ms并非耗時任務(wù)的執(zhí)行時間,而我們的自定義信息msg=slowCall cost=2000才包含了真正的耗時。

penaltyDeath(),當觸發(fā)違規(guī)條件時,直接Crash掉當前應(yīng)用程序。

penaltyDeathOnNetwork(),當觸發(fā)網(wǎng)絡(luò)違規(guī)時,Crash掉當前應(yīng)用程序。

penaltyDialog(),觸發(fā)違規(guī)時,顯示對違規(guī)信息對話框。

penaltyFlashScreen(),會造成屏幕閃爍,不過一般的設(shè)備可能沒有這個功能。

penaltyDropBox(),將違規(guī)信息記錄到 dropbox 系統(tǒng)日志目錄中(/data/system/dropbox),你可以通過如下命令進行插件:

adb shell dumpsys dropbox dataappstrictmode --print

permitCustomSlowCalls()、permitDiskReads ()、permitDiskWrites()、permitNetwork: 如果你想關(guān)閉某一項檢測,可以使用對應(yīng)的permit*方法。

VMPolicy 詳解

StrictMode.VmPolicy.Builder 主要方法如下

detectActivityLeaks() 用戶檢查 Activity 的內(nèi)存泄露情況

內(nèi)存泄露檢查案例:

public class MainActivity extends AppCompatActivity implements View.OnClickListener { @Override protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_main);  StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()    .detectActivityLeaks()    .penaltyLog()    .build()  );  new Thread() {   @Override   public void run() {    while (true) {     SystemClock.sleep(1000);    }   }  }.start(); }}

我們反復(fù)旋轉(zhuǎn)屏幕就會輸出提示信息(重點在 instances=2; limit=1 這一行)

嚴苛模式,android,strictmode

       這時因為,我們在Activity中創(chuàng)建了一個Thread匿名內(nèi)部類,而匿名內(nèi)部類隱式持有外部類的引用。而每次旋轉(zhuǎn)屏幕是,Android會新創(chuàng)建一個Activity,而原來的Activity實例又被我們啟動的匿名內(nèi)部類線程持有,所以不會釋放,從日志上看,當先系統(tǒng)中該Activty有4個實例,而限制是只能創(chuàng)建1各實例。我們不斷翻轉(zhuǎn)屏幕,instances 的個數(shù)還會持續(xù)增加。

detectLeakedClosableObjects()用于資源沒有正確關(guān)閉時提醒

// 資源引用沒有關(guān)閉檢查案例public class MainActivity extends AppCompatActivity implements View.OnClickListener { @Override protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_main);  StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()    .detectLeakedClosableObjects()    .penaltyLog()    .build()  );  File newxmlfile = new File(Environment.getExternalStorageDirectory(), "castiel.txt");  try {   newxmlfile.createNewFile();   FileWriter fw = new FileWriter(newxmlfile);   fw.write("猴子搬來的救兵WooYun");   //fw.close(); 我們在這里特意沒有關(guān)閉 fw  } catch (IOException e) {   e.printStackTrace();  } }}

運行后觸發(fā)警告如下

嚴苛模式,android,strictmode

  • detectLeakedSqlLiteObjects() 和
  • detectLeakedClosableObjects()的用法類似,只不過是用來檢查 SQLiteCursor 或者 其他 SQLite
  • 對象是否被正確關(guān)閉
  • detectLeakedRegistrationObjects() 用來檢查 BroadcastReceiver 或者
  • ServiceConnection 注冊類對象是否被正確釋放
  • setClassInstanceLimit(),設(shè)置某個類的同時處于內(nèi)存中的實例上限,可以協(xié)助檢查內(nèi)存泄露

檢測內(nèi)存泄露案例

public class MainActivity extends AppCompatActivity implements View.OnClickListener { private static class CastielClass{} private static List<CastielClass> classList; @Override protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_main);  classList = new ArrayList<CastielClass>();  StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()    .setClassInstanceLimit(CastielClass.class, 2)    .penaltyLog()    .build());  classList.add(new CastielClass());  classList.add(new CastielClass());  classList.add(new CastielClass());  classList.add(new CastielClass());  classList.add(new CastielClass());  classList.add(new CastielClass());  classList.add(new CastielClass());  classList.add(new CastielClass()); }}

運行后觸發(fā)警告如下

嚴苛模式,android,strictmode

其他操作

       除了通過日志查看之外,我們也可以在開發(fā)者選項中開啟嚴格模式,開啟之后,如果主線程中有執(zhí)行時間長的操作,屏幕則會閃爍,這是一個更加直接的方法。

嚴苛模式,android,strictmode

注意事項

  • 只在開發(fā)階段啟用StrictMode,發(fā)布應(yīng)用或者release版本一定要禁用它。
  • 嚴格模式無法監(jiān)控JNI中的磁盤IO和網(wǎng)絡(luò)請求。
  • 應(yīng)用中并非需要解決全部的違例情況,比如有些IO操作必須在主線程中進行。

總結(jié)

以上所述是小編給大家介紹的Android嚴苛模式StrictMode使用詳解,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對VEVB武林網(wǎng)網(wǎng)站的支持!


注:相關(guān)教程知識閱讀請移步到Android開發(fā)頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 佛教| 淳化县| 博客| 宁陕县| 长沙县| 满城县| 右玉县| 天峻县| 宁南县| 八宿县| 大厂| 阳新县| 安图县| 沙河市| 石城县| 锡林郭勒盟| 丽水市| 东莞市| 扎鲁特旗| 镇平县| 洛浦县| 长治市| 微山县| 凉城县| 海安县| 喀喇沁旗| 永仁县| 巨野县| 福安市| 海安县| 隆尧县| 南丹县| 平舆县| 红河县| 龙胜| 桐梓县| 聊城市| 新密市| 永泰县| 德州市| 大新县|