基于Method Trace工具解決UI卡頓的問題

??????? 很久以前就看過使用Android studio的Method Trace工具調(diào)查函數(shù)性能或者效率的問題,一直沒有在解決日常問題過程中實戰(zhàn)過。最近剛好遇到了一個關(guān)閉wifi開關(guān)時wifi設(shè)置頁面卡頓的問題,所以就想著嘗試一下。雖然解決UI卡頓一般都用systrace工具,但是method trace可以查看各個線程中某個函數(shù)執(zhí)行情況,理論上也是可以用來定位UI卡頓問題的。

首先啟動method trace功能,然后關(guān)閉wifi,待卡頓過后,停止trace。Android studio會自動打開抓取的內(nèi)容。?

雖然Eclipse通過ddms抓取的traceview也是可以查看函數(shù)調(diào)用情況,但是Adroid studio的method trace功能更強(qiáng)大,尤其是可以分線程查看,這就更方便我們查找問題了。由于UI卡頓肯定是主線程被block了,必然我們要看這段時間內(nèi)主線程的執(zhí)行情況。選中上圖中的主線程,可以看到中間有個很長的長條,鼠標(biāo)放上去之后,發(fā)現(xiàn)該函數(shù)執(zhí)行了約1.5s(注意起始時間,與后面做對比時可以很方便確認(rèn)多線程調(diào)用時函數(shù)執(zhí)行先后順序),那么可以確認(rèn),就是這個函數(shù)出的問題了。

定位到源碼中的copyAndNotifyListeners函數(shù),去掉其他邏輯后主邏輯如下

private void copyAndNotifyListeners(boolean notifyListeners) {

……1……

???? synchronized (mLock) {

??????? ……2……

??? }

……3……

}

直觀的懷疑是執(zhí)行完1處的邏輯之后,主線程要去拿鎖,此時由于鎖被其他線程占用,所以主線程要一直等待。但是這只是我們的懷疑,要找到證據(jù)才行。這又要體現(xiàn)出Method Trace工具的強(qiáng)大之處。圖中的每個小方格都代表了函數(shù)的執(zhí)行情況,包括函數(shù)名、函數(shù)執(zhí)行時間以及各個函數(shù)之間的調(diào)用情況。原理上,如果邏輯2中有函數(shù)調(diào)用的話,必定能在圖中體現(xiàn)出來。把圖中卡頓地方前后位置放大之后,發(fā)現(xiàn)卡頓之前確實在調(diào)用1處的函數(shù),而在卡頓之后恰好在調(diào)用2處的邏輯。這樣,就為我們之前的假設(shè)找到了證據(jù)。

既然主線程要取的鎖被占用,肯定是被其他線程占用著,具體是什么線程,可以通過圖中左上角查看每個線程的調(diào)用情況來確認(rèn)。果然,在某個線程中我們發(fā)現(xiàn)了與主線程類似的長條。查看函數(shù)調(diào)用堆棧的情況,確實在該函數(shù)中持有對應(yīng)的鎖,且該鎖剛好是在主線程之前拿到的。這樣卡頓的原因就找到了。進(jìn)一步分析,該部分卡頓是由于子線程在持鎖期間調(diào)用了WifiManager的接口,而這個接口在向WifiManager取數(shù)據(jù)時采用的是同步調(diào)用,而WifiManager最終是向WifiStateMachine中取數(shù)據(jù),WifiStateMachine線程此時正在忙碌調(diào)用driver中的接口,無法及時處理這個請求,因此這就是應(yīng)用層被卡住的原因。

雖然經(jīng)過上面的分析,問題是WifiStateMachine引起的,但是一款優(yōu)秀的應(yīng)用,還是要首先檢查自己能否兼容這種場景,自己的邏輯是否也存在問題。深入分析之后發(fā)現(xiàn),子線程確實存在持鎖范圍過大的問題,可以進(jìn)行優(yōu)化,避免不必要的等待。

補(bǔ)充問題

在解決上面問題時,對android源碼的@GuardedBy標(biāo)記有些疑惑,這個標(biāo)記有啥作用呢?我直觀的以為這個可以當(dāng)成一把鎖來用,但這只是我的假設(shè)而已,肯定要驗證一下才能踏實。查閱了一些資料,感覺還是云里霧里,所以還是自己做實驗看看把。

寫了上面的測試代碼,編譯之后得到.class文件,通過javap -c Test.class后查看編譯后的代碼

從這個結(jié)果可以看出,@GuardedBy標(biāo)簽并沒有對編譯后的結(jié)果產(chǎn)生影響,也就沒有同步作用。事實上該標(biāo)簽和@Override標(biāo)簽的功能是一致的,更多的作用是一種標(biāo)記,標(biāo)記這個變量或者這個函數(shù)是需要同步的,同時編譯器在編譯時可以根據(jù)這些標(biāo)簽做lint檢查之類的工作。在日常工作中,可以合理的使用這些標(biāo)簽以增強(qiáng)代碼邏輯的可讀性,同時也方便其他同學(xué)閱讀此處邏輯時能更快的領(lǐng)會設(shè)計意圖。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時...
    歐辰_OSR閱讀 30,271評論 8 265
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,678評論 19 139
  • 1、2014年8月14號,研究生舍友陳給我打電話,說無聊就給我打個電話。我對她表達(dá)了有了愛情之后就忘了我的牢騷,說...
    janet閱讀 253評論 0 1
  • 先來個圖吧 大概的效果就是這樣,代碼就一個監(jiān)聽事件,把需要移動的View添加這個監(jiān)聽事件就可以了,具體的參數(shù)要根據(jù)...
    隔壁老王的雜貨鋪閱讀 883評論 0 0
  • 典韋,東漢末年曹操部將,相貌魁梧,力大過人,一對鐵戟,好不霸氣。本屬張邈,后歸曹操。曹操征討呂布時被募為陷陣,表現(xiàn)...
    老爺子l閱讀 896評論 0 0

友情鏈接更多精彩內(nèi)容