Android性能調優利器StrictMode

mayday 7年前發布 | 4K 次閱讀 安卓開發 Android開發 移動開發

作為Android開發,日常的開發工作中或多或少要接觸到性能問題,比如我的Android程序運行緩慢卡頓,并且常常出現ANR對話框等等問題。既然有性能問題,就需要進行性能優化。正所謂工欲善其事,必先利其器。一個好的工具,可以幫助我們發現并定位問題,進而有的放矢進行解決。本文主要介紹StrictMode 在Android 應用開發中的應用和一些問題。

什么是StrictMode

StrictMode意思為嚴格模式,是用來檢測程序中違例情況的開發者工具。最常用的場景就是檢測主線程中本地磁盤和網絡讀寫等耗時的操作。

嚴在哪里

既然叫做嚴格模式,那么又嚴格在哪些地方呢?

在Android中,主線程,也就是UI線程,除了負責處理UI相關的操作外,還可以執行文件讀取或者數據庫讀寫操作(從Android 4.0 開始,網絡操作禁止在主線程中執行,否則會拋出 NetworkOnMainThreadException )。使用嚴格模式,系統檢測出主線程違例的情況會做出相應的反應,如日志打印,彈出對話框亦或者崩潰等。換言之,嚴格模式會將應用的違例細節暴露給開發者方便優化與改善。

具體能檢測什么

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

ThreadPolicy

線程策略檢測的內容有

  • 自定義的耗時調用 使用 detectCustomSlowCalls() 開啟
  • 磁盤讀取操作 使用 detectDiskReads() 開啟
  • 磁盤寫入操作 使用 detectDiskWrites() 開啟
  • 網絡操作 使用 detectNetwork() 開啟

VmPolicy

虛擬機策略檢測的內容有

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

工作原理

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

@Override
public 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() 方法的實現,代碼位于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);
}

如何使用

關于StrictMode如何使用,最重要的就是如何啟用嚴格模式。

放在哪里

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

簡單啟用

以下的代碼啟用全部的ThreadPolicy和VmPolicy違例檢測

if (IS_DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {  
    StrictMode.setThreadPolicy(new         
    StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());      
    StrictMode.setVmPolicy(new VmPolicy.Builder().detectAll().penaltyLog().build());
}

嚴格模式需要在debug模式開啟,不要在release版本中啟用。

同時,嚴格模式自API 9 開始引入,某些API方法也從 API 11 引入。使用時應該注意 API 級別。

如有需要,也可以開啟部分的嚴格模式。

查看結果

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

adb logcat | grep StrictMode

解決違例

  • 如果是主線程中出現文件讀寫違例,建議使用工作線程(必要時結合Handler)完成。
  • 如果是對SharedPreferences寫入操作,在API 9 以上 建議優先調用apply而非commit。
  • 如果是存在未關閉的Closable對象,根據對應的stacktrace進行關閉。
  • 如果是SQLite對象泄露,根據對應的stacktrace進行釋放。

其他技巧

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

問題來了

通常情況下StrictMode給出的耗時相對實際情況偏高,并不是真正的耗時數據。

  • 在線上環境即Release版本不建議開啟嚴格模式。
  • 嚴格模式無法監控JNI中的磁盤IO和網絡請求。
  • 應用中并非需要解決全部的違例情況,比如有些IO操作必須在主線程中進行。

 

來自:http://www.jianshu.com/p/eb1f0b5301ee

 

 本文由用戶 mayday 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!