作為Android開發(fā),日常的開發(fā)工作中或多或少要接觸到性能問題,比如我的Android程序運(yùn)行緩慢卡頓,并且常常出現(xiàn)ANR對(duì)話框等等問題奕扣。既然有性能問題,就需要進(jìn)行性能優(yōu)化掌敬。正所謂工欲善其事惯豆,必先利其器。一個(gè)好的工具奔害,可以幫助我們發(fā)現(xiàn)并定位問題楷兽,進(jìn)而有的放矢進(jìn)行解決。本文主要介紹StrictMode 在Android 應(yīng)用開發(fā)中的應(yīng)用和一些問題华临。
什么是StrictMode
StrictMode意思為嚴(yán)格模式芯杀,是用來檢測(cè)程序中違例情況的開發(fā)者工具。最常用的場(chǎng)景就是檢測(cè)主線程中本地磁盤和網(wǎng)絡(luò)讀寫等耗時(shí)的操作雅潭。
嚴(yán)在哪里
既然叫做嚴(yán)格模式瘪匿,那么又嚴(yán)格在哪些地方呢?
在Android中寻馏,主線程,也就是UI線程核偿,除了負(fù)責(zé)處理UI相關(guān)的操作外诚欠,還可以執(zhí)行文件讀取或者數(shù)據(jù)庫讀寫操作(從Android 4.0 開始,網(wǎng)絡(luò)操作禁止在主線程中執(zhí)行漾岳,否則會(huì)拋出NetworkOnMainThreadException)轰绵。使用嚴(yán)格模式,系統(tǒng)檢測(cè)出主線程違例的情況會(huì)做出相應(yīng)的反應(yīng)尼荆,如日志打印左腔,彈出對(duì)話框亦或者崩潰等。換言之捅儒,嚴(yán)格模式會(huì)將應(yīng)用的違例細(xì)節(jié)暴露給開發(fā)者方便優(yōu)化與改善液样。
具體能檢測(cè)什么
嚴(yán)格模式主要檢測(cè)兩大問題振亮,一個(gè)是線程策略,即TreadPolicy鞭莽,另一個(gè)是VM策略坊秸,即VmPolicy。
ThreadPolicy
線程策略檢測(cè)的內(nèi)容有
- 自定義的耗時(shí)調(diào)用 使用detectCustomSlowCalls()開啟
- 磁盤讀取操作 使用detectDiskReads()開啟
- 磁盤寫入操作 使用detectDiskWrites()開啟
- 網(wǎng)絡(luò)操作 使用detectNetwork()開啟
VmPolicy
虛擬機(jī)策略檢測(cè)的內(nèi)容有
- Activity泄露 使用detectActivityLeaks()開啟
- 未關(guān)閉的Closable對(duì)象泄露 使用detectLeakedClosableObjects()開啟
- 泄露的Sqlite對(duì)象 使用detectLeakedSqlLiteObjects()開啟
- 檢測(cè)實(shí)例數(shù)量 使用setClassInstanceLimit()開啟
工作原理
其實(shí)StrictMode實(shí)現(xiàn)原理也比較簡(jiǎn)單澎怒,以IO操作為例褒搔,主要是通過在open,read喷面,write星瘾,close時(shí)進(jìn)行監(jiān)控。libcore.io.BlockGuardOs
文件就是監(jiān)控的地方惧辈。以open為例琳状,如下進(jìn)行監(jiān)控
@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()方法的實(shí)現(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);
}
如何使用
關(guān)于StrictMode如何使用算撮,最重要的就是如何啟用嚴(yán)格模式。
放在哪里
嚴(yán)格模式的開啟可以放在Application或者Activity以及其他組件的onCreate方法县昂。為了更好地分析應(yīng)用中的問題肮柜,建議放在Application的onCreate方法中。
簡(jiǎn)單啟用
以下的代碼啟用全部的ThreadPolicy和VmPolicy違例檢測(cè)
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());
}
嚴(yán)格模式需要在debug模式開啟倒彰,不要在release版本中啟用审洞。
同時(shí),嚴(yán)格模式自API 9 開始引入待讳,某些API方法也從 API 11 引入芒澜。使用時(shí)應(yīng)該注意 API 級(jí)別。
如有需要创淡,也可以開啟部分的嚴(yán)格模式痴晦。
查看結(jié)果
嚴(yán)格模式有很多種報(bào)告違例的形式,但是想要分析具體違例情況琳彩,還是需要查看日志誊酌,終端下過濾StrictMode就能得到違例的具體stacktrace信息。
adb logcat | grep StrictMode
解決違例
- 如果是主線程中出現(xiàn)文件讀寫違例露乏,建議使用工作線程(必要時(shí)結(jié)合Handler)完成碧浊。
- 如果是對(duì)SharedPreferences寫入操作,在API 9 以上 建議優(yōu)先調(diào)用apply而非commit瘟仿。
- 如果是存在未關(guān)閉的Closable對(duì)象箱锐,根據(jù)對(duì)應(yīng)的stacktrace進(jìn)行關(guān)閉。
- 如果是SQLite對(duì)象泄露劳较,根據(jù)對(duì)應(yīng)的stacktrace進(jìn)行釋放驹止。
其他技巧
除了通過日志查看之外浩聋,我們也可以在開發(fā)者選項(xiàng)中開啟嚴(yán)格模式,開啟之后幢哨,如果主線程中有執(zhí)行時(shí)間長的操作赡勘,屏幕則會(huì)閃爍,這是一個(gè)更加直接的方法捞镰。
問題來了
通常情況下StrictMode給出的耗時(shí)相對(duì)實(shí)際情況偏高闸与,并不是真正的耗時(shí)數(shù)據(jù)。
- 在線上環(huán)境即Release版本不建議開啟嚴(yán)格模式岸售。
- 嚴(yán)格模式無法監(jiān)控JNI中的磁盤IO和網(wǎng)絡(luò)請(qǐng)求践樱。
- 應(yīng)用中并非需要解決全部的違例情況,比如有些IO操作必須在主線程中進(jìn)行凸丸。