Android UI卡頓原因及解決辦法

渲染機(jī)制介紹

為了分析UI卡頓,我們有必要理解一下渲染機(jī)制,這套渲染機(jī)制適用于絕大部分的屏幕渲染,其中包括Android手機(jī)等眾多屏幕設(shè)備。

渲染的一些重要參數(shù):

屏幕刷新理想的頻率(硬件的角度):60Hz

理想的一秒內(nèi)繪制的幀數(shù),幀率(屏幕刷新的角度):60fps

這兩個(gè)參數(shù)都是理想值,指代的都是同一個(gè)概念。實(shí)際情況中難免會(huì)比它們低。在60fps內(nèi),系統(tǒng)會(huì)得到發(fā)送的VSYNC(垂直刷新/繪制)信號(hào)去進(jìn)行渲染,就會(huì)正常地繪制出我們需要的圖形界面。Android手機(jī)進(jìn)行繪制的時(shí)候,GPU幫助我們將UI組件等計(jì)算成紋理Texture和三維圖形Polygons,同時(shí)會(huì)使用OpenGL---會(huì)將紋理和Polygons緩存在GPU內(nèi)存里面。

其中,VSYNC:有兩個(gè)概念

Refresh Rate:屏幕在一秒時(shí)間內(nèi)刷新屏幕的次數(shù)----有硬件的參數(shù)決定,比如60HZ,即屏幕每秒刷新60次

Frame Rate:GPU在一秒內(nèi)繪制操作的幀數(shù),比如:60fps,

基本結(jié)論

要達(dá)到60fps,就要求:每一幀只能停留16ms。(大概就是1000ms/60 ~= 16ms刷新一次)


內(nèi)存抖動(dòng)是因?yàn)榇罅康膶?duì)象被創(chuàng)建又在短時(shí)間內(nèi)馬上被釋放。

?瞬間產(chǎn)生大量的對(duì)象會(huì)嚴(yán)重占用Young Generation的內(nèi)存區(qū)域,當(dāng)達(dá)到閥值,剩余空間不夠的時(shí)候,也會(huì)觸發(fā)GC。即使每次分配的對(duì)象占用了很少的內(nèi)存,但是他們疊加在一起會(huì)增加Heap的壓力,從而觸發(fā)更多其他類型的GC。這個(gè)操作有可能會(huì)影響到幀率,并使得用戶感知到性能問(wèn)題。

Android里面是一個(gè)三級(jí)Generation的內(nèi)存模型,最近分配的對(duì)象會(huì)存放在Young Generation區(qū)域,當(dāng)這個(gè)對(duì)象在這個(gè)區(qū)域停留的時(shí)間達(dá)到一定程度,它會(huì)被移動(dòng)到Old Generation,最后到Permanent Generation區(qū)域。


Android系統(tǒng)里面有一個(gè)Generational Heap Memory的模型,系統(tǒng)會(huì)根據(jù)內(nèi)存中不同的內(nèi)存數(shù)據(jù)類型分別執(zhí)行不同的GC操作。例如,最近剛分配的對(duì)象會(huì)放在Young Generation區(qū)域,這個(gè)區(qū)域的對(duì)象通常都是會(huì)快速被創(chuàng)建并且很快被銷毀回收的,同時(shí)這個(gè)區(qū)域的GC操作速度也是比Old Generation區(qū)域的GC操作速度更快。

UI卡頓分析

Android每個(gè)16ms就會(huì)繪制一次Activity,通過(guò)上述的結(jié)論我們知道,如果由于一些原因?qū)е铝宋覀兊倪壿?、CPU耗時(shí)、GPU耗時(shí)大于16ms(應(yīng)用卡頓的根源就在于16ms內(nèi)不能完成繪制渲染合成過(guò)程,16ms需要完成視圖樹(shù)的所有測(cè)量、布局、繪制渲染及合成),UI就無(wú)法完成一次繪制,那么就會(huì)造成卡頓。

比如說(shuō),在16ms內(nèi),發(fā)生了頻繁的GC:

在第一個(gè)16ms內(nèi),UI正常地完成了繪制,那么屏幕不會(huì)卡頓。

在第二個(gè)16ms內(nèi),由于某些原因觸發(fā)了頻發(fā)的GC,UI無(wú)法在16ms內(nèi)完成繪制,就會(huì)卡頓。

UI卡頓外部和內(nèi)部常見(jiàn)原因

下面總結(jié)一些常見(jiàn)的UI卡頓原因:

?1.內(nèi)存抖動(dòng)的問(wèn)題

?2.方法太耗時(shí)了(CPU占用)

耗時(shí)原因分析

? ? 1)CPU計(jì)算時(shí)間,CPU的測(cè)量、布局時(shí)間

????2)CPU將計(jì)算好的Polygons和Texture傳遞到GPU的時(shí)候也需要時(shí)間。OpenGL ES API允許數(shù)據(jù)上傳到GPU后可以對(duì)數(shù)據(jù)進(jìn)行保存,緩存到display list。因此,我們平移等操作一個(gè)view是幾乎不怎么耗時(shí)的。

? ? 3)GPU進(jìn)行格柵化

當(dāng)我們的布局是用的FrameLayout的時(shí)候,我們可以把它改成merge,可以避免自己的幀布局和系統(tǒng)的ContentFrameLayout幀布局重疊造成重復(fù)計(jì)算(measure和layout)。

使用ViewStub:當(dāng)加載的時(shí)候才會(huì)占用。不加載的時(shí)候就是隱藏的,僅僅占用位置。

CPU優(yōu)化建議

針對(duì)CPU的優(yōu)化,從減輕加工View對(duì)象成Polygons和Texture來(lái)下手:

View Hierarchy中包涵了太多的沒(méi)有用的view,這些view根本就不會(huì)顯示在屏幕上面,一旦觸發(fā)測(cè)量和布局操作,就會(huì)拖累應(yīng)用的性能表現(xiàn)。那么我們就需要利用工具進(jìn)行分析。

如何找出里面沒(méi)用的view呢?或者減少不必要的view嵌套。

我們利用工具:Hierarchy Viewer進(jìn)行檢測(cè),優(yōu)化思想是:查看自己的布局,層次是否很深以及渲染比較耗時(shí),然后想辦法能否減少層級(jí)以及優(yōu)化每一個(gè)View的渲染時(shí)間。

我們打開(kāi)APP,然后打開(kāi)Android Device Monitor,然后切換到Hierarchy Viewer面板。除了看層次結(jié)構(gòu)之外,還可以看到一些耗時(shí)的信息:

三個(gè)圓點(diǎn)分別代表:測(cè)量、布局、繪制三個(gè)階段的性能表現(xiàn)。

1)綠色:渲染的管道階段,這個(gè)視圖的渲染速度快于至少一半的其他的視圖。

2)黃色:渲染速度比較慢的50%。

3)紅色:渲染速度非常慢。

GPU優(yōu)化建議

GPU優(yōu)化建議就是一句話:盡量避免過(guò)度繪制(overdraw)

一、背景經(jīng)常容易造成過(guò)度繪制。

手機(jī)開(kāi)發(fā)者選項(xiàng)里面找到工具:Debug GPU overdraw,其中,不同顏色代表了繪制了幾次:


藍(lán)色,淡綠,淡紅,深紅代表了4種不同程度的Overdraw情況,我們的目標(biāo)就是盡量減少紅色Overdraw,看到更多的藍(lán)色區(qū)域。Overdraw有時(shí)候是因?yàn)槟愕腢I布局存在大量重疊的部分,還有的時(shí)候是因?yàn)榉潜仨毜闹丿B背景。例如某個(gè)Activity有一個(gè)背景,然后里面的Layout又有自己的背景,同時(shí)子View又分別有自己的背景。僅僅是通過(guò)移除非必須的背景圖片,這就能夠減少大量的紅色Overdraw區(qū)域,增加藍(lán)色區(qū)域的占比。這一措施能夠顯著提升程序性能。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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