卡頓分析和布局優(yōu)化

大多數(shù)用戶感知到的卡頓等性能問題的最主要根源都是因?yàn)殇秩拘阅芪⒎澹珹ndroid系統(tǒng)每隔大概16.6ms發(fā)出的VSYNC信號(hào)燕刻,觸發(fā)對(duì)UI進(jìn)行渲染,如果每次渲染都成功沫换,這樣就能夠達(dá)到流暢的畫面所需要的60fps类浪,為了能夠?qū)崿F(xiàn)60fps载城,這意味著程序的大多數(shù)操作都必須在16ms內(nèi)完成。

我們通常都會(huì)提到60fps與16ms费就,可是知道為何會(huì)是以程序是否達(dá)到60fps來作為APP性能的衡量標(biāo)準(zhǔn)嗎诉瓦?這是因?yàn)槿搜叟c大腦之間的寫作無法感知超過60fps的畫面更新。

12fps大概類似手動(dòng)快速翻動(dòng)的幀率力细,這明顯是可以感知到不夠順滑的垦搬。24fps使得人眼感知的是連續(xù)線性的運(yùn)動(dòng),這其實(shí)是歸功于運(yùn)動(dòng)模糊的效果艳汽,24fps是電影膠圈通常使用的幀率猴贰,因?yàn)檫@個(gè)幀率已經(jīng)足夠支撐大部分電影畫面需要表達(dá)的內(nèi)容,同時(shí)能夠最大的減少費(fèi)用支出河狐。但是低于30fps是無法順暢表現(xiàn)絢麗的畫面內(nèi)容的米绕,此時(shí)就需要用到60fps來達(dá)到想要的效果瑟捣,當(dāng)然超過60fps是沒有必要的。

開發(fā)app的性能目標(biāo)就是保持60fps栅干,這意味著每一幀你只有16ms=1000/60的時(shí)間來處理所有的任務(wù)迈套。

如果某個(gè)操作花費(fèi)時(shí)間是24ms,系統(tǒng)在得到VSYNV信號(hào)的時(shí)候就無法進(jìn)行正常渲染碱鳞,這樣就發(fā)生了丟幀現(xiàn)象桑李,那么用戶在32ms內(nèi)看到的會(huì)是同一幀畫面。

有很多原因可以導(dǎo)致丟幀窿给,一般主線程過多的UI繪制贵白、大量的IO操作或是大量操作占用CPU,都會(huì)導(dǎo)致App界面卡頓崩泡。

更詳細(xì)的描述請(qǐng)參考Android圖形顯示系統(tǒng)https://blog.csdn.net/a740169405/article/details/70548443

卡頓分析工具CPU Profile介紹

最基本的介紹參考官網(wǎng)https://developer.android.google.cn/studio/profile/cpu-profiler
實(shí)際的操作中如何使用呢禁荒,如果你發(fā)現(xiàn)你的某個(gè)操作有點(diǎn)卡頓,這時(shí)候你就可以使用這個(gè)工具進(jìn)行查找原因角撞,先點(diǎn)擊cpu profile按鈕呛伴,這時(shí)候有兩種配置方式

選擇記錄配置.png

Sample Java Methods
對(duì)Java方法采樣:在應(yīng)用的Java代碼執(zhí)行期間,頻繁捕獲應(yīng)用的調(diào)用堆棧谒所,分析器會(huì)比較捕獲的數(shù)據(jù)集热康,以推導(dǎo)與應(yīng)用的Java代碼執(zhí)行有關(guān)的時(shí)間和資源使用信息。如果應(yīng)用在捕獲調(diào)用堆棧后進(jìn)入一個(gè)方法并在下次捕獲前退出該方法劣领,分析器將不會(huì)記錄該方法調(diào)用姐军。如果您想要跟蹤生命周期如此短的方法,應(yīng)使用檢測跟蹤剖踊。
Trace Java Methods
跟蹤 Java 方法:在運(yùn)行時(shí)檢測應(yīng)用庶弃,以在每個(gè)方法調(diào)用開始和結(jié)束時(shí)記錄一個(gè)時(shí)間戳衫贬。系統(tǒng)會(huì)收集并比較這
些時(shí)間戳德澈,以生成方法跟蹤數(shù)據(jù),包括時(shí)間信息和 CPU 使用率固惯。
可以根據(jù)自己的需要進(jìn)行選擇梆造,然后我們點(diǎn)擊Record進(jìn)行記錄,這時(shí)候我們進(jìn)行手機(jī)上面的操作葬毫,當(dāng)操作完成后點(diǎn)擊 Stop recording镇辉,這時(shí)候就會(huì)生成對(duì)應(yīng)的跟蹤信息
跟蹤信息

然后我們可以進(jìn)行分析,逐步排查卡頓的原因贴捡。
還有一種方式可以生成對(duì)應(yīng)的跟蹤信息忽肛,在開始記錄的位置使用startMethodTracingSampling(String tracePath, int bufferSize,int intervalUs)進(jìn)行采樣
,三個(gè)參數(shù)代表生成trace文件的位置烂斋,文件大小還有采樣的時(shí)間間隔
或者startMethodTracing(String tracePath, int bufferSize, int flags)進(jìn)行跟蹤,
三個(gè)參數(shù)代表生成trace文件的位置屹逛,文件大小還有一個(gè)標(biāo)志設(shè)置础废,bufferSize參數(shù)指定了trace文件的最大值。Trace信息可以使用很多空間罕模,你的存儲(chǔ)器可能是有限的评腺,所以嘗試去使用一個(gè)可接受的值(默認(rèn)8M)。安卓現(xiàn)在只定義一個(gè)標(biāo)志淑掌,Debug.TRACE_COUNT_ALLOCS.
設(shè)置了之后我們就可以在對(duì)應(yīng)的位置找到trace文件蒿讥,使用AS工具打開進(jìn)行問題查找了。

布局優(yōu)化

層級(jí)優(yōu)化
使用Layout Inspector

Layout Inspector工具.png

然后選擇需要查看的進(jìn)程與Activity:
布局檢查器.png

Layout Inspector主要用來分析布局的層級(jí)結(jié)構(gòu)抛腕,減少不必要的層級(jí)芋绸,更加詳細(xì)的介紹參考官網(wǎng)https://developer.android.google.cn/studio/debug/layout-inspector?hl=zh_cn

使用merge標(biāo)簽

merge標(biāo)簽是用來幫助在視圖樹中減少重復(fù)布局的,當(dāng)某個(gè)layout布局被多次引用時(shí)兽埃,可以使用merge侥钳,減少嵌套
可參考文章https://blog.csdn.net/a740169405/article/details/50473909

使用ViewStub標(biāo)簽

當(dāng)我們布局中存在一個(gè)View/ViewGroup,在某個(gè)特定時(shí)刻才需要它的展示時(shí)柄错,可能會(huì)使用gone或者invisible舷夺,在需要顯示時(shí)再設(shè)置visible可見。
viewStub是一個(gè)輕量級(jí)的view售貌,它不可見给猾,不用占用資源,只有設(shè)置viewstub為visible或者調(diào)用其inflater()方法時(shí)颂跨,其對(duì)應(yīng)的布局文件才會(huì)被初始化敢伸。
可參考詳細(xì)的文章https://blog.csdn.net/a740169405/article/details/50351013

過度渲染

過度渲染是指系統(tǒng)在渲染單個(gè)幀的過程中多次在屏幕上繪制某一個(gè)像素,例如恒削,如果我們有若干界面卡片堆疊在一起池颈,每張卡片都會(huì)遮蓋其下面一張卡片的部分內(nèi)容,但是钓丰,系統(tǒng)仍然需要繪制堆疊中的卡片被遮蓋的部分躯砰。
GPU過度繪制檢查
手機(jī)開發(fā)者選項(xiàng)中能夠顯示過度渲染檢查功能,通過對(duì)界面進(jìn)行彩色編碼來幫我們識(shí)別過度繪制携丁,開啟步驟如下:
1.進(jìn)入開發(fā)者選項(xiàng)
2.找到調(diào)試GPU過度繪制
3.在彈出的對(duì)話框中琢歇,選擇顯示過度繪制區(qū)域
Android 將按如下方式為界面元素著色,以確定過度繪制的次數(shù):

參考過度繪制.png

更加詳細(xì)的介紹參考官網(wǎng)https://developer.android.google.cn/topic/performance/rendering/inspect-gpu-rendering?hl=zh_cn

解決過度繪制問題

可以通過以下方法來減少過度繪制
1.移除布局中不需要的背景
默認(rèn)情況下梦鉴,布局沒有背景李茫,這表示布局本身不會(huì)直接渲染任何內(nèi)容,但是當(dāng)布局具有背景時(shí)肥橙,其有可能會(huì)導(dǎo)致過度繪制
移除不必要的背景可以快速提高渲染性能魄宏,不必要的背景可能永遠(yuǎn)不可見,因?yàn)樗鼤?huì)被在該視圖上繪制的任何其他內(nèi)容完全覆蓋存筏,例如宠互,當(dāng)系統(tǒng)在父視圖上繪制子視圖時(shí)塔次,可能會(huì)完全覆蓋父視圖的背景。
2.使視圖層次結(jié)構(gòu)扁平化
可以通過優(yōu)化視圖層次結(jié)構(gòu)來減少重疊界面對(duì)象的數(shù)量名秀,從而提高性能励负。
3.降低透明度
對(duì)于不透明的view,只需要渲染一次就可以顯示出來匕得,但是如果這個(gè)view設(shè)置了alpha值继榆,則至少需要渲染兩次,這是因?yàn)槭褂昧薬lpha的view需要先知道混合view的下一層元素是什么汁掠,然后再結(jié)合上層的view進(jìn)行混色處理略吨。透明動(dòng)畫、淡入淡出和陰影等都涉及到某種透明度考阱,這就會(huì)造成了過度繪制翠忠。可以通過減少要渲染的透明對(duì)象的數(shù)量乞榨,來改善這些情況下的過度繪制秽之,例如,如需獲得灰色文本吃既,可以在TextView中繪制黑色文本,再為其設(shè)置半透明的透明度值,但是,簡單地通過用灰色繪制文本也能獲得同樣的效果,而且能夠大幅提升性能考榨。

布局加載優(yōu)化

LayoutInflater加載xml布局的過程會(huì)在主線程使用IO讀取XML布局文件進(jìn)行XML解析,再根據(jù)解析結(jié)果利用反射 創(chuàng)建布局中的View/ViewGroup對(duì)象鹦倚。這個(gè)過程隨著布局的復(fù)雜度上升河质,耗時(shí)自然也會(huì)隨之增大。Android為我們 提供了 Asynclayoutinflater 把耗時(shí)的加載操作在異步線程中完成震叙,最后把加載結(jié)果再回調(diào)給主線程掀鹅。
dependencies {
implementation "androidx.asynclayoutinflater:asynclayoutinflater:1.0.0"
}
new AsyncLayoutInflater(this)
.inflate(R.layout.activity_main, null, new AsyncLayoutInflater.OnInflateFinishedListener() { @Override
public void onInflateFinished(@NonNull View view, int resid, @Nullable ViewGroup parent) {
setContentView(view);
//......
} });
1、使用異步 inflate媒楼,那么需要這個(gè) layout 的 parent 的 generateLayoutParams 函數(shù)是線程安全的; 2乐尊、所有構(gòu)建的 View 中必須不能創(chuàng)建 Handler 或者是調(diào)用 Looper.myLooper;(因?yàn)槭窃诋惒骄€程中加載的,異
步線程默認(rèn)沒有調(diào)用 Looper.prepare );
3匣砖、AsyncLayoutInflater 不支持設(shè)置 LayoutInflater.Factory 或者 LayoutInflater.Factory2; 4科吭、不支持加載包含 Fragment 的 layout
5昏滴、如果 AsyncLayoutInflater 失敗猴鲫,那么會(huì)自動(dòng)回退到UI線程來加載布局

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市谣殊,隨后出現(xiàn)的幾起案子拂共,更是在濱河造成了極大的恐慌,老刑警劉巖姻几,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宜狐,死亡現(xiàn)場離奇詭異势告,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)抚恒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門咱台,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人俭驮,你說我怎么就攤上這事回溺。” “怎么了混萝?”我有些...
    開封第一講書人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵遗遵,是天一觀的道長。 經(jīng)常有香客問我逸嘀,道長车要,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任崭倘,我火速辦了婚禮翼岁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘司光。我一直安慰自己登澜,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開白布飘庄。 她就那樣靜靜地躺著脑蠕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪跪削。 梳的紋絲不亂的頭發(fā)上谴仙,一...
    開封第一講書人閱讀 51,258評(píng)論 1 300
  • 那天,我揣著相機(jī)與錄音碾盐,去河邊找鬼晃跺。 笑死,一個(gè)胖子當(dāng)著我的面吹牛毫玖,可吹牛的內(nèi)容都是我干的掀虎。 我是一名探鬼主播,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼付枫,長吁一口氣:“原來是場噩夢啊……” “哼烹玉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起阐滩,我...
    開封第一講書人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤二打,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后掂榔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體继效,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡症杏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瑞信。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片厉颤。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖凡简,靈堂內(nèi)的尸體忽然破棺而出走芋,到底是詐尸還是另有隱情,我是刑警寧澤潘鲫,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布翁逞,位于F島的核電站,受9級(jí)特大地震影響溉仑,放射性物質(zhì)發(fā)生泄漏挖函。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一浊竟、第九天 我趴在偏房一處隱蔽的房頂上張望怨喘。 院中可真熱鬧,春花似錦振定、人聲如沸必怜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽梳庆。三九已至,卻和暖如春卑惜,著一層夾襖步出監(jiān)牢的瞬間膏执,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來泰國打工露久, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留更米,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓毫痕,卻偏偏與公主長得像征峦,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子消请,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容