终于有人把安卓程序员必学知识点全整理出来了,送大厂面经一份!
除了Bug,最讓你頭疼的問題是什么?單身?禿頭?996?面試造火箭,工作擰螺絲?
作為安卓開發(fā)者,除了Bug,經(jīng)常會碰到下面這些問題:
應(yīng)用卡頓,丟幀,屏幕畫面撕裂,操作界面刷新緩慢,UI不美觀,布局混亂…這些問題頻發(fā)的話,年后可能就不用來了。
開發(fā)App的時(shí)候,你是否會覺得界面卡頓?尤其是自定義View的時(shí)候。
Android 應(yīng)用的卡頓、丟幀等,這些影響用戶體驗(yàn)的因素絕大部分都與 16ms 這個(gè)值有關(guān)。Android 設(shè)備的刷新率也是 60Hz,Android系統(tǒng)每隔16ms發(fā)出VSYNC信號,觸發(fā)對UI進(jìn)行渲染,如果超過了16ms,我們則認(rèn)為發(fā)生了卡頓。
二、顯示系統(tǒng)基礎(chǔ)知識
在一個(gè)典型的顯示系統(tǒng)中,一般包括CPU、GPU、Display三個(gè)部分, CPU負(fù)責(zé)計(jì)算幀數(shù)據(jù),把計(jì)算好的數(shù)據(jù)交給GPU,GPU會對圖形數(shù)據(jù)進(jìn)行渲染,渲染好后放到buffer(圖像緩沖區(qū))里存起來,然后Display(屏幕或顯示器)負(fù)責(zé)把buffer里的數(shù)據(jù)呈現(xiàn)到屏幕上。如下圖:
2.1 基礎(chǔ)概念
-
屏幕刷新頻率 一秒內(nèi)屏幕刷新的次數(shù)(一秒內(nèi)顯示了多少幀的圖像),單位 Hz(赫茲),如常見的 60 Hz。刷新頻率取決于硬件的固定參數(shù)(不會變的)。
-
逐行掃描 顯示器并不是一次性將畫面顯示到屏幕上,而是從左到右邊,從上到下逐行掃描,順序顯示整屏的一個(gè)個(gè)像素點(diǎn),不過這一過程快到人眼無法察覺到變化。以 60 Hz 刷新率的屏幕為例,這一過程即 1000 / 60 ≈ 16ms。
-
幀率 (Frame Rate) 表示 GPU 在一秒內(nèi)繪制操作的幀數(shù),單位 fps。例如在電影界采用 24 幀的速度足夠使畫面運(yùn)行的非常流暢。而 Android 系統(tǒng)則采用更加流程的 60 fps,即每秒鐘GPU最多繪制 60 幀畫面。幀率是動態(tài)變化的,例如當(dāng)畫面靜止時(shí),GPU 是沒有繪制操作的,屏幕刷新的還是buffer中的數(shù)據(jù),即GPU最后操作的幀數(shù)據(jù)。
-
畫面撕裂(tearing) 一個(gè)屏幕內(nèi)的數(shù)據(jù)來自2個(gè)不同的幀,畫面會出現(xiàn)撕裂感,如下圖
2.2 雙緩存
2.2.1 畫面撕裂 原因
屏幕刷新頻是固定的,比如每16.6ms從buffer取數(shù)據(jù)顯示完一幀,理想情況下幀率和刷新頻率保持一致,即每繪制完成一幀,顯示器顯示一幀。但是CPU/GPU寫數(shù)據(jù)是不可控的,所以會出現(xiàn)buffer里有些數(shù)據(jù)根本沒顯示出來就被重寫了,即buffer里的數(shù)據(jù)可能是來自不同的幀的, 當(dāng)屏幕刷新時(shí),此時(shí)它并不知道buffer的狀態(tài),因此從buffer抓取的幀并不是完整的一幀畫面,即出現(xiàn)畫面撕裂。
簡單說就是Display在顯示的過程中,buffer內(nèi)數(shù)據(jù)被CPU/GPU修改,導(dǎo)致畫面撕裂。
2.2.2 雙緩存
那咋解決畫面撕裂呢? 答案是使用 雙緩存。
由于圖像繪制和屏幕讀取 使用的是同個(gè)buffer,所以屏幕刷新時(shí)可能讀取到的是不完整的一幀畫面。
雙緩存,讓繪制和顯示器擁有各自的buffer:GPU 始終將完成的一幀圖像數(shù)據(jù)寫入到 Back Buffer,而顯示器使用 Frame Buffer,當(dāng)屏幕刷新時(shí),Frame Buffer 并不會發(fā)生變化,當(dāng)Back buffer準(zhǔn)備就緒后,它們才進(jìn)行交換。如下圖:
2.2.3 VSync
問題又來了:什么時(shí)候進(jìn)行兩個(gè)buffer的交換呢?
假如是 Back buffer準(zhǔn)備完成一幀數(shù)據(jù)以后就進(jìn)行,那么如果此時(shí)屏幕還沒有完整顯示上一幀內(nèi)容的話,肯定是會出問題的。看來只能是等到屏幕處理完一幀數(shù)據(jù)后,才可以執(zhí)行這一操作了。
當(dāng)掃描完一個(gè)屏幕后,設(shè)備需要重新回到第一行以進(jìn)入下一次的循環(huán),此時(shí)有一段時(shí)間空隙,稱為VerticalBlanking Interval(VBI)。那,這個(gè)時(shí)間點(diǎn)就是我們進(jìn)行緩沖區(qū)交換的最佳時(shí)間。因?yàn)榇藭r(shí)屏幕沒有在刷新,也就避免了交換過程中出現(xiàn) screen tearing的狀況。
VSync(垂直同步)是VerticalSynchronization的簡寫,它利用VBI時(shí)期出現(xiàn)的vertical sync pulse(垂直同步脈沖)來保證雙緩沖在最佳時(shí)間點(diǎn)才進(jìn)行交換。另外,交換是指各自的內(nèi)存地址,可以認(rèn)為該操作是瞬間完成。
所以說V-sync這個(gè)概念并不是Google首創(chuàng)的,它在早年的PC機(jī)領(lǐng)域就已經(jīng)出現(xiàn)了。
三、Android屏幕刷新機(jī)制
3.1 Android4.1之前的問題
具體到Android中,在Android4.1之前,屏幕刷新也遵循 上面介紹的 雙緩存+VSync 機(jī)制。如下圖:
以時(shí)間的順序來看下將會發(fā)生的過程:
所以總的來說,就是屏幕平白無故地多顯示了一次第1幀。
原因是 第2幀的CPU/GPU計(jì)算 沒能在VSync信號到來前完成 。
我們知道,雙緩存的交換 是在Vsyn到來時(shí)進(jìn)行,交換后屏幕會取Frame buffer內(nèi)的新數(shù)據(jù),而實(shí)際 此時(shí)的Back buffer 就可以供GPU準(zhǔn)備下一幀數(shù)據(jù)了。 如果 Vsyn到來時(shí) CPU/GPU就開始操作的話,是有完整的16.6ms的,這樣應(yīng)該會基本避免jank的出現(xiàn)了(除非CPU/GPU計(jì)算超過了16.6ms)。 那如何讓 CPU/GPU計(jì)算在 Vsyn到來時(shí)進(jìn)行呢?
3.2 drawing with VSync
為了優(yōu)化顯示性能,Google在Android 4.1系統(tǒng)中對Android Display系統(tǒng)進(jìn)行了重構(gòu),實(shí)現(xiàn)了Project Butter(黃油工程):系統(tǒng)在收到VSync pulse后,將馬上開始下一幀的渲染。即一旦收到VSync通知(16ms觸發(fā)一次),CPU和GPU 才立刻開始計(jì)算然后把數(shù)據(jù)寫入buffer。如下圖:
CPU/GPU根據(jù)VSYNC信號同步處理數(shù)據(jù),可以讓CPU/GPU有完整的16ms時(shí)間來處理數(shù)據(jù),減少了jank。
一句話總結(jié),VSync同步使得CPU/GPU充分利用了16.6ms時(shí)間,減少jank。
問題又來了,如果界面比較復(fù)雜,CPU/GPU的處理時(shí)間較長 超過了16.6ms呢?如下圖:
為什么 CPU 不能在第二個(gè) 16ms 處理繪制工作呢?
原因是只有兩個(gè) buffer,Back buffer正在被GPU用來處理B幀的數(shù)據(jù), Frame buffer的內(nèi)容用于Display的顯示,這樣兩個(gè)buffer都被占用,CPU 則無法準(zhǔn)備下一幀的數(shù)據(jù)。 那么,如果再提供一個(gè)buffer,CPU、GPU 和顯示設(shè)備都能使用各自的buffer工作,互不影響。
3.3 三緩存
三緩存就是在雙緩沖機(jī)制基礎(chǔ)上增加了一個(gè) Graphic Buffer 緩沖區(qū),這樣可以最大限度的利用空閑時(shí)間,帶來的壞處是多使用的一個(gè) Graphic Buffer 所占用的內(nèi)存。
第一個(gè)Jank,是不可避免的。但是在第二個(gè) 16ms 時(shí)間段,CPU/GPU 使用 第三個(gè) Buffer 完成C幀的計(jì)算,雖然還是會多顯示一次 A 幀,但后續(xù)顯示就比較順暢了,有效避免 Jank 的進(jìn)一步加劇。
注意在第3段中,A幀的計(jì)算已完成,但是在第4個(gè)vsync來的時(shí)候才顯示,如果是雙緩沖,那在第三個(gè)vynsc就可以顯示了。
三緩沖有效利用了等待vysnc的時(shí)間,減少了jank,但是帶來了延遲。 所以,是不是 Buffer 越多越好呢?這個(gè)是否定的,Buffer 正常還是兩個(gè),當(dāng)出現(xiàn) Jank 后三個(gè)足以。
以上就是Android屏幕刷新的原理了。
小結(jié)
有了這么多優(yōu)秀的開發(fā)工具,可以做出更高質(zhì)量的Android應(yīng)用。
當(dāng)然了,“打鐵還需自身硬”,想要寫出優(yōu)秀的代碼,最重要的一點(diǎn)還是自身的技術(shù)水平,不然用再好的工具也不能發(fā)揮出它的全部實(shí)力。
在這里我也分享一份大佬自己收錄整理的Android學(xué)習(xí)PDF+架構(gòu)視頻+面試文檔+源碼筆記,還有高級架構(gòu)技術(shù)進(jìn)階腦圖、Android開發(fā)面試專題資料,高級進(jìn)階架構(gòu)資料這些都是我閑暇還會反復(fù)翻閱的精品資料。在腦圖中,每個(gè)知識點(diǎn)專題都配有相對應(yīng)的實(shí)戰(zhàn)項(xiàng)目,可以有效的幫助大家掌握知識點(diǎn)。
總之也是在這里幫助大家學(xué)習(xí)提升進(jìn)階,也節(jié)省大家在網(wǎng)上搜索資料的時(shí)間來學(xué)習(xí),也可以分享給身邊好友一起學(xué)習(xí)
oid開發(fā)面試專題資料,高級進(jìn)階架構(gòu)資料**這些都是我閑暇還會反復(fù)翻閱的精品資料。在腦圖中,每個(gè)知識點(diǎn)專題都配有相對應(yīng)的實(shí)戰(zhàn)項(xiàng)目,可以有效的幫助大家掌握知識點(diǎn)。
總之也是在這里幫助大家學(xué)習(xí)提升進(jìn)階,也節(jié)省大家在網(wǎng)上搜索資料的時(shí)間來學(xué)習(xí),也可以分享給身邊好友一起學(xué)習(xí)
如果你有需要的話,可以點(diǎn)擊這里領(lǐng)取
總結(jié)
以上是生活随笔為你收集整理的终于有人把安卓程序员必学知识点全整理出来了,送大厂面经一份!的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: lol和dota的区别是什么?
- 下一篇: 试管婴儿年龄最大的多大了