我們平常開發中的那些控件,比如Button,TextView,是如何渲染到屏幕上的呢?
簡而言之,就是現先將xml解析成相應的對象,然後CPU經過計算以後將圖形信息傳給GPU,GPU來負責繪製,柵格化等操作,最終顯示到手機屏幕上。
Android每16ms對屏幕進行一次刷新,當一幀畫面渲染時間超過16ms的時候,垂直同步機制會讓顯示器硬件等待GPU完成柵格化渲染操作,最後在下一次VSync信號到來時才顯示到屏幕上,這樣就會讓這一幀畫面,在屏幕上多停留了16ms
如上圖
Step1. Display顯示第0幀數據,此時CPU和GPU渲染第1幀畫面,而且趕在Display顯示下一幀前完成
Step2. 因爲渲染及時,Display在第0幀顯示完成後,也就是第1個VSync後,正常顯示第1幀
Step3. 由於某些原因,比如CPU資源被佔用,系統沒有及時地開始處理第2幀,直到第2個VSync快來前纔開始處理
Step4. 第2個VSync來時,由於第2幀數據還沒有準備就緒,顯示的還是第1幀。這種情況被Android開發組命名爲「Jank」。
Step5. 當第2幀數據準備完成後,它並不會馬上被顯示,而是要等待下一個VSync。
所以總的來說,就是屏幕平白無故地多顯示了一次第1幀。原因大家應該都看到了,就是CPU沒有及時地開始着手處理第2幀的渲染工作,以致「延誤軍機」。
試想用戶盯着同一張圖看了32ms而不是16ms,當然很容易察覺出卡頓感,哪怕僅僅出現一次掉幀,用戶都會發現動畫不是很順暢。
16 毫秒的時間主要被兩件事情所佔用
第一件:將 UI 對象轉換爲一系列多邊形和紋理
第二件: CPU 傳遞處理數據到 GPU 。所以很明顯,我們要縮短
這兩部分的時間,也就是說需要儘量減少對象轉換的次數,以及上傳數據的次數
如何減少這兩部分的時間 以至於在 16ms 完成呢?
(1)CPU 減少 xml 轉換成對象的時間(去掉重複的、減少不必要的佈局,儘量扁平化)
(2)GPU 減少重複繪製的時間
GPU的繪製過程,就跟刷牆一樣,一層一層地進行,16ms刷一次。這樣就會造成,圖層覆蓋的現象,即無用的圖層還被繪製在底層,造成不必要的浪費
GPU過度繪製的幾種情況
過度繪製查看工具
在手機端的開發者選項裏,裏面有個調試GPU過度繪製工具
點擊以後會發現你的屏幕變得紅紅綠綠的,這些顏色就代表了特定部分過度繪製的程度
可以看到,這裏的RecyclerView佈局列表項重複繪製了四次,導致畫面十分卡頓。
通過分析,我們發現問題有以下幾個:
其實還有更多方法來減少過度繪製,優化我們的性能。
可以在TextView中加上drawableLeft來設置圖片,避免使用imageView+TextView的方式。
因爲所有的佈局解析都要消耗cpu的計算性能,所以Layout並不是越多越好。
自定義View優化的重點主要在Canvas上,例如出現幾個View互相層疊時(卡牌式),可以通過裁剪畫布防止過度繪製
在Android Studio 的Android Device Monitor中直接打開這個工具
然後打開我們要檢測的app,然後
之後可以看到我們的View樹,
看到這個簡直崩潰了,太多了。
我們看到視圖中幾乎所有節點都有三個點,顏色也各不相同
這三個點也是代表着View的Measure, Layout和Draw。
不同顏色意味着不同的速度:
綠: 表示該View的此項性能比該View Tree中超過50%的View都要快;例如,代表Measure的是綠點,意味着這個視圖的測量時間快於樹中的視圖對象的50%。
黃: 表示該View的此項性能比該View Tree中超過50%的View都要慢;
紅: 表示該View的此項性能是View Tree中最慢的。
可以很清楚的分辨清不同View的性能以及Measure, Layout和Draw的時間,通過紅色的View節點進去查看,佈局是否有不合理之處。
優化方式