溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

Android中卡頓優(yōu)化布局實(shí)例分析

發(fā)布時(shí)間:2022-01-24 13:35:02 來(lái)源:億速云 閱讀:116 作者:柒染 欄目:開(kāi)發(fā)技術(shù)

小編今天帶大家了解Android中卡頓優(yōu)化布局實(shí)例分析,文中知識(shí)點(diǎn)介紹的非常詳細(xì)。覺(jué)得有幫助的朋友可以跟著小編一起瀏覽文章的內(nèi)容,希望能夠幫助更多想解決這個(gè)問(wèn)題的朋友找到問(wèn)題的答案,下面跟著小編一起深入學(xué)習(xí)“Android中卡頓優(yōu)化布局實(shí)例分析”的知識(shí)吧。

背景

在當(dāng)下移動(dòng)互聯(lián)網(wǎng)后半場(chǎng),手機(jī)已經(jīng)是人手必備的設(shè)備。App是離用戶(hù)最近的應(yīng)用,界面又是最直觀(guān)影響用戶(hù)體驗(yàn)的關(guān)鍵部分,其流暢度直接影響用戶(hù)對(duì)產(chǎn)品的評(píng)價(jià)和留存。

技術(shù)是服務(wù)于人的,如果技術(shù)無(wú)法給你帶來(lái)良好的體驗(yàn),那技術(shù)本身的存在就具有爭(zhēng)議。

所以界面性能是至關(guān)重要的,不可忽視。

實(shí)踐過(guò)程

布局代碼是最基礎(chǔ)的,但也是最重要的。

首先我們看個(gè)簡(jiǎn)單小案例

Android中卡頓優(yōu)化布局實(shí)例分析

不同深淺的顏色來(lái)表示過(guò)度繪制:

沒(méi)顏色:沒(méi)有過(guò)度繪制,即一個(gè)像素點(diǎn)繪制了 1 次,顯示應(yīng)用本來(lái)的顏色;

藍(lán)色:1倍過(guò)度繪制,即一個(gè)像素點(diǎn)繪制了 2 次;

綠色:2倍過(guò)度繪制,即一個(gè)像素點(diǎn)繪制了 3 次;

淺紅色:3倍過(guò)度繪制,即一個(gè)像素點(diǎn)繪制了 4 次;

深紅色:4倍過(guò)度繪制及以上,即一個(gè)像素點(diǎn)繪制了 5 次及以上;

如何渲染界面

CPU(中央處理器) :我們經(jīng)常聽(tīng)到,是計(jì)算機(jī)的核心器件,多緩存多分支,適用于復(fù)雜的邏輯運(yùn)算,主要負(fù)責(zé)Measure,Layout,Record,Execute的計(jì)算操作

GPU(圖像處理器):我們通常說(shuō)的顯卡核心就是它了。用于結(jié)構(gòu)單一的數(shù)據(jù)處理(擅長(zhǎng)圖形計(jì)算),主要負(fù)責(zé)Rasterization(柵格化)操作

谷歌官方對(duì)于流暢度的優(yōu)化也是高度重視的,有界面渲染三核心Vsync、Triple Buffer和Choreographer。

為何是16ms/為何每秒60幀

android系統(tǒng)每隔16ms繪制一幀UI且要在16ms內(nèi)完成,( 1秒 / 0.016幀每秒 = 62.5幀/秒 )差不多每秒更新60次。這是因?yàn)槲覀兇竽X和眼睛一般看24Fps的畫(huà)面就已經(jīng)是連續(xù)的運(yùn)動(dòng)了,看60Fps的畫(huà)面更看不出端倪,但是60幀可以表達(dá)出更加絢麗多彩的內(nèi)容。

一旦沒(méi)及時(shí)繪制,就會(huì)出現(xiàn)掉幀問(wèn)題,也就是常說(shuō)的卡頓。這是因?yàn)槔L制的東西太多的話(huà),CPU、GPU處理不及時(shí)。

當(dāng)然了,設(shè)備性能越好,處理能力越強(qiáng),卡頓會(huì)越少,玩游戲的電腦配置高也是出于這方面考慮。

那么Android是如何把圖像繪制到界面上的呢?

這就用到了上面的CPU/GPU。

GPU負(fù)責(zé)柵格化操作(Resterization),柵格化是繪制那些Button,Shape,Path,String,Bitmap等組件最基礎(chǔ)的操作。它把那些組件拆分到不同的像素上進(jìn)行顯示。這是一個(gè)很“費(fèi)時(shí)”的操作(相比人類(lèi)時(shí)間只是眨眼的功夫),GPU的引入就是為了加快柵格化的操作。

CPU負(fù)責(zé)把UI組件計(jì)算成Polygons,Texture紋理,然后交給GPU進(jìn)行柵格化渲染。流程如下:

Android中卡頓優(yōu)化布局實(shí)例分析

為了能夠使得App流暢,我們需要在每一幀16ms以?xún)?nèi)處理完所有的CPU與GPU計(jì)算,繪制,渲染等等操作。

有興趣更深層學(xué)習(xí)的,可以去看看界面渲染容器DisplayList

什么是過(guò)度繪制

Overdraw(過(guò)度繪制)描述的是屏幕上的某個(gè)像素在同一幀的時(shí)間內(nèi)被繪制了N次。但是我們只能看到最上層的UI,這就會(huì)導(dǎo)致多層次的UI界面除最上層外對(duì)用戶(hù)都是不可見(jiàn)的,這樣就會(huì)浪費(fèi)大量的CPU以及GPU資源,浪費(fèi)可恥。

這就像我們?cè)诩埳瞎潭▍^(qū)域不斷圖畫(huà),但是有最上層最接近你,其他層有個(gè)鬼用?

如何查看繪制維度

開(kāi)發(fā)工具有Hierarchy View、Systrace、Track等

真機(jī)在開(kāi)發(fā)者選項(xiàng)中有:調(diào)試GPU繪制、硬件層更新、GPU視圖更新等等

界面優(yōu)化

在編寫(xiě)Android布局時(shí)總會(huì)遇到這樣或者那樣的痛點(diǎn),比如:

1.有些布局的在很多頁(yè)面都用到了,而且樣式都一樣,每次用到都要復(fù)制粘貼一大段,有沒(méi)有辦法可以復(fù)用呢?2.解決了1中的問(wèn)題之后,發(fā)現(xiàn)復(fù)用的布局外面總要額外套上一層布局,要知道布局嵌套是會(huì)影響性能的吶;3.有些布局只有用到時(shí)才會(huì)顯示,但是必須提前寫(xiě)好,雖然設(shè)置了為invisible或gone,還是多多少少會(huì)占用內(nèi)存的。

首先第一點(diǎn)也是最重要的一點(diǎn),在剛開(kāi)始寫(xiě)布局的時(shí)候一定要提前想好和規(guī)劃好,盡可能的減少層級(jí)的嵌套。往往越復(fù)雜的布局越臃腫,越容易被忽視進(jìn)而出現(xiàn)性能問(wèn)題,所以我們寫(xiě)布局就要知道一些技巧來(lái)展示布局

1. 如果圖片和文字在一起且文字不動(dòng)態(tài)變的話(huà),可以直接使用帶文字的圖片。

2. 移除沒(méi)用的布局和控件,假設(shè)添加個(gè)背景,盡可能在已經(jīng)布局上放,減少只有背景功能的控件。

3. 減少透明度的使用,假設(shè):#55FFFFFF 和 #888888 顏色類(lèi)似,建議使用后者,因?yàn)榍罢哂蠥lpha,view需要至少繪制兩次。

4. 去掉多余的不可見(jiàn)顏色背景、圖片等,只保留最上層用戶(hù)可見(jiàn)即可

5. 減少布局層次結(jié)構(gòu),避免多層嵌套推薦使用RelativeLayout、ConstraintLayout等父類(lèi)布局

6. 基本控件LinearLayout 性能比RelativeLayout高一些,要提前根據(jù)UI想好哪個(gè)布局更合適,要有的方式,對(duì)癥下藥。

7. 自定義View盡可能只更新渲染局部區(qū)域,杜絕不斷全部重繪。

8. 推薦使用IDE自帶的Lint或者阿里代碼檢查插件,對(duì)于標(biāo)黃警告等提示重視起來(lái),能改的就改。

除了以上,我們就要解決過(guò)度繪制,我們還可以使用抽象布局,它們分別是include、merge和ViewStub三個(gè)標(biāo)簽,現(xiàn)在我們就來(lái)認(rèn)識(shí)認(rèn)識(shí)它們吧。

Include應(yīng)該是最常用的了,其翻譯是“包含”、“包括”,最佳使用就是把相同代碼抽離出來(lái)成一個(gè)獨(dú)立的xml文件,當(dāng)你在某個(gè)布局需要使用的時(shí)候直接include進(jìn)來(lái),這樣一搞,很好地起到復(fù)用布局的效果。不僅可以極大地減少代碼量,想要修改的話(huà)直接改這一個(gè)xml就行了。

它的兩個(gè)主要屬性:layout:必填屬性, id屬性;

我們還可以重寫(xiě)寬高、邊距和可見(jiàn)性(visibility)這些布局屬性。但是一定要注意,單單重寫(xiě)android:layout_height或者android:layout_width是不行,必須兩個(gè)同時(shí)重寫(xiě)才起作用。

這些也能玩不不少花樣。

Merge介紹

凡事都有利有弊include標(biāo)簽除了上面的優(yōu)點(diǎn),也有個(gè)問(wèn)題就是布局嵌套。他必須有一個(gè)根布局,這也導(dǎo)致了最終布局嵌套層級(jí)可能多一層。

這時(shí)候又引出個(gè)新的標(biāo)簽標(biāo)簽,這次先說(shuō)他的局限性:就是你需要提前明確要放到什么父布局中,然后提前設(shè)置好merge里面的控件位置。

優(yōu)點(diǎn)也明顯:他是消除多余層級(jí)的,標(biāo)簽必須作為根節(jié)點(diǎn)出現(xiàn)。不占用空間,他只是將子view“搬運(yùn)”到你想嵌套的位置。

ViewStub

寫(xiě)布局的時(shí)候我們經(jīng)常會(huì)遇到有些效果不必一直顯示,需要?jiǎng)討B(tài)的來(lái)設(shè)置invisible或gone,這無(wú)形中影響了頁(yè)面加載速度。

Android提供的方案就是ViewStub,他是一個(gè)不可見(jiàn)的大小為0的視圖,具有懶加載功能,存在于視圖中,但只有設(shè)置setVisibility()和inflate()方法調(diào)用后才會(huì)渲染填充視圖,能為初始化加載xml布局分散壓力,就像負(fù)載均衡。

使用案例:進(jìn)度條,加載網(wǎng)絡(luò)失敗,顯示錯(cuò)誤消息等等

它有以下三個(gè)重要屬性:

android:layout:ViewStub需要填充的視圖名稱(chēng),為“R.layout.xx”的形式;

android:inflateId:重寫(xiě)被填充的視圖的父布局id。

與include標(biāo)簽不同,ViewStub的android:id屬性是設(shè)置ViewStub本身id的,而不是重寫(xiě)布局id,這一點(diǎn)可不要搞錯(cuò)了。另外,ViewStub還提供了OnInflateListener接口,用于監(jiān)聽(tīng)布局是否已經(jīng)加載了。

但是注意 viewStub.inflate();方法不能多次調(diào)用,否則拋出異常:

java.lang.IllegalStateException: ViewStubmusthaveanon-nullViewGroupviewParent

原因是ViewStub源碼調(diào)用了removeViewInLayout()方法把自己從布局移除了。到這里我們就明白了,ViewStub在填充布局成功之后就會(huì)自我銷(xiāo)毀,再次調(diào)用inflate()方法就會(huì)拋出IllegalStateException異常了。此時(shí)如果想要再次顯示布局,可以調(diào)用setVisibility()方法。

還有一個(gè)大坑:viewStub.getVisibility()的值一直為0,所以用他來(lái)判斷是否顯示沒(méi)作用。不要急,其實(shí)是setVisibility()方法實(shí)際上在設(shè)置內(nèi)部視圖的可見(jiàn)性,而不是ViewStub本身。

硬件加速原理

Android中卡頓優(yōu)化布局實(shí)例分析

相信經(jīng)??吹接械奈恼抡f(shuō)開(kāi)啟硬件加速解決卡的問(wèn)題,但硬件加速是什么呢?

硬件加速的主要原理是通多底層邏輯,將CPU不擅長(zhǎng)的圖形計(jì)算轉(zhuǎn)換成GPU專(zhuān)用指令,讓更擅長(zhǎng)圖形計(jì)算的GPU來(lái)完成渲染。

硬件加速過(guò)程中包含兩個(gè)步驟 :

構(gòu)建階段 : 遍歷所有視圖,將需要繪制的操作緩存下來(lái),交給單獨(dú)的Render線(xiàn)程使用GPU進(jìn)行硬件加速渲染。(這一階段在主線(xiàn)程中使用CPU構(gòu)建)

繪制階段 : 調(diào)用OpenGL(即使用GPU)對(duì)構(gòu)建好的視圖進(jìn)行繪制渲染,繪制的內(nèi)容保存在Graphic Buffer 并交由 SurfaceFlinger 顯示。(Android 5.0+ 使用Render Thread線(xiàn)程,專(zhuān)門(mén)負(fù)責(zé) UI 渲染和動(dòng)畫(huà)顯示。)

以上證得硬件加速具有不錯(cuò)的優(yōu)點(diǎn),但它不是萬(wàn)能的。

我們平時(shí)用的時(shí)候可能是直接在Application中用,一鍋端,這并不嚴(yán)謹(jǐn),因?yàn)橛布铀龠€沒(méi)法做到支持所有的繪制操作(比如復(fù)雜的自定義View),這樣的話(huà)就會(huì)造成一定的影響:

1. 像素錯(cuò)位等視覺(jué)問(wèn)題

2. 不同設(shè)備版本API兼容問(wèn)題

解決這些問(wèn)題官方給了解決方案:使用四種級(jí)別控制是否硬件加速。

1. Application

Android中卡頓優(yōu)化布局實(shí)例分析

2. Activity-為單獨(dú)頁(yè)面設(shè)置

Android中卡頓優(yōu)化布局實(shí)例分析

3. Window級(jí)別

Android中卡頓優(yōu)化布局實(shí)例分析

4. 單獨(dú)的view級(jí)別關(guān)閉加速(View目前不支持動(dòng)態(tài)啟動(dòng)硬件加速)

Android中卡頓優(yōu)化布局實(shí)例分析

感謝大家的閱讀,以上就是“Android中卡頓優(yōu)化布局實(shí)例分析”的全部?jī)?nèi)容了,學(xué)會(huì)的朋友趕緊操作起來(lái)吧。相信億速云小編一定會(huì)給大家?guī)?lái)更優(yōu)質(zhì)的文章。謝謝大家對(duì)億速云網(wǎng)站的支持!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI