Android性能優化-渲染

你好,我是老七,很高興能夠分享一些我在學習過程中的收穫,本文是學習Google官方渲染UI的學習筆記,如果本文幫助到你了,希望不要吝嗇你的小小喜歡點個心,你的支持是我堅持的動力,接下來就步入正題了,集中你的注意力,性能優化之車要發車了~

性能渲染的定義

Android系統每隔16ms重新繪製一次Activity,也就意味着應用需要在16ms內完成屏幕刷新的全部邏輯操作,這樣才能達到每秒60幀.

1000ms/60hz = 16.666ms/frame

image.png

這個每秒幀數的參數實際上來源於手機硬件,定義了屏幕每秒刷新速度有多快,這意味着你有60ms的時間去完成每幀的繪製邏輯操作,如果錯過了,比如你花費了24ms才完成計算,那麼就會出現我們所稱之爲丟幀的情況.
image.png

Android系統嘗試在屏幕上繪製新的一幀,但是這一陣還沒有準備好,所以畫面就不會刷新,就會造成用戶盯着同一張圖看了32ms而不是16ms,丟幀情況下運行的任何動畫就會使用戶很容易察覺出卡頓感,哪怕僅僅出現一次丟幀,用戶都會發現動畫不是很流暢,如果出現多次丟幀,用戶就會開始抱怨卡頓,如果此時用戶正在和系統進行交互操作,例如滑動列表或者輸入數據,那麼卡頓感就會更加明顯,用戶就會開啓吐槽模式~
只有我們對繪製每幀花費的時間有更清晰的瞭解後才能發現是什麼原因導致了卡頓,該如何去解決應用中的這些問題.

渲染管道

Android系統的渲染管道分爲兩個關鍵組件:CPU、GPU


image.png

兩者共同工作在屏幕上繪製圖片,每個組件都有自身定義的特定流程,你必須遵守這些特定的操作規則才能達到效果.

常見的性能問題

CPU

最常見的性能問題是不必要的佈局和失效,這些內容必須在師徒層次結構中進行測量、清除並重新創建,而引發這種問題通常有兩個原因,一是重建顯示列表的次數太多,二是花費太多時間作廢視圖層次並進行不必要的重繪.這兩個原因在更新顯示列表,或者其他緩存GPU資源時導致CPU工作過度.

GPU

最常見的問題就是過度繪製,通常是在像素着色過程中,通過其他工具進行後期着色時,浪費了GPU的處理時間
[圖片上傳中...(image.png-d82fb7-1538205529526-0)]

接下來將介紹更多關於失效、佈局和重繪的內容以及如何使用SDK中提供的可用工具找出影響應用性能的原因並且舉例說明如何修復應用中的此類問題.

過度繪製

要想開發一款性能優越的應用,你必須瞭解底層是如何運行的,如果不知道硬件是如何運行就無法熟練使用它.
首先我們要知道:Activity是如何繪製到屏幕上的,那些負責的XML佈局文件和標記語言是如何轉化成用戶能看懂的圖像的?
實際上,這是由光柵化操作來完成的.


image.png

光柵化將注入字符串、按鈕、路徑或者形狀的一些高級對象拆分到不同的像素上在屏幕上進行顯示,並且光柵化是一個非常費時的操作.也就是說你的手機裏有一塊特殊硬件,目的就是加快光柵化的操作,圖像處理單元,也就是GPU.
GPU是在上個世紀90年代被引入主流電腦,幫助加快光柵化操作,現在,GPU使用一些指定的基礎指令集,主要是多邊形和紋理,也就是圖片,CPU在屏幕上繪製圖像前會向GPU輸入這些指令,這一過程通常使用的API就是Android的OpenGL ES,這就是說,在屏幕上繪製UI對象時,無論是按鈕、路徑、或者複選框都需要在CPU中首先轉換爲多邊形或者紋理,然後再傳遞給GPU進行光柵化.
你可以想象一下,一個UI對象轉換爲一系列多邊形和紋理的過程,肯定是相當耗時的,從CPU上傳處理數據到GPU同樣也很耗時,所以很明顯,你需要儘量減少對象轉換的次數以及上傳數據的次數,幸虧OpenGL ES的API允許數據上傳到GPU後可以對數據進行保存,當你下次繪製一個按鈕時,只需要在GPU存儲器裏引用它,然後告訴OpenGL如何繪製.
到了這裏我們就可以應該可以想到,渲染性能的優化就是儘可能快的上傳數據到GPU,然後儘可能長地在不修改的條件下保存數據,因爲每次上傳資源到GPU時,你都會浪費寶貴的處理時間.
Android系統的Honeycomb(API Level 11)版本發佈之後,整個UI渲染系統就在GPU中運行,之後各個版本都在渲染系統性能方面有更多改進,Android系統在降低、重新利用GPU資源方面做了很多工作,所以在這方面我們完全不用擔心,舉個例子說,任何你的主題所提供的資源,例如Bitmaps、Drawables等都是一起打包到統一的紋理當中,然後利用網格工具上傳到GPU,例如Nine Patches等,這樣每次你需要繪製這些資源時就不用做任何轉換,因爲他們已經存儲在GPU中了,大大加快了這些視圖類型的顯示.
然而隨着UI對象的不斷升級,渲染流程也變得越來越複雜,例如說繪製圖像就是把圖片上傳到CPU存儲器,然後傳遞到GPU中進行渲染,路徑使用是完全另一回事,你需要在CPU中創建一系列的多邊形,甚至在GPU中創建掩蔽紋理來定義路徑,繪製字符更加複雜一些,首先我們需要在CPU中把字符繪製成圖像,然後把圖像上傳到GPU進行渲染再返回到CPU,在屏幕上爲字符串的每個字符繪製一個正方形.
現在Android系統已經解決了大多數性能問題,除非你還有更高的要求,你基本不會發現與GPU相關的問題,然而還有一個GPU性能問題瓶頸,這個問題困擾着每個程序開發人員,這就是過度繪製.
如果你曾經畫過一個房間或房子,你應該知道在那些牆上塗滿顏色會花費很多功夫,如果你需要重新畫一遍,那你第一次做這件事時就浪費了很多功夫.相同的,浪費精力去繪製某些東西同樣可能會對應用程序中的性能問題產生影響,所以,在性能和設計的交匯處存在一個共同的性能問題-過度繪製.


image.png

過度繪製是一個術語,用來描述屏幕上的一個像素在一幀中被重畫了多少次,例如,如果我們有一堆層疊的UI,上面的UI層級會遮蓋住底下的UI層級,意味着我們花費很多時間繪製的圖層大部分是不可見的,實際上這是一個很大的問題,因爲每次我們渲染的像素對最終場景沒有幫助,我們就浪費了GPU的性能.使用這樣的佈局,我們很容易陷入一個陷阱.分層的視圖給了我們這個美麗的,卓越的設計,但同樣也導致了過渡繪製的問題.爲了最大化應用程序的性能,你需要使用最小化的過渡繪製.


image.png

幸運的是,在Android設備上很容易看到應用程序中過度繪製的數量.進入手機的開發者模式,打開GPU過渡繪製的功能,你的手機界面可能會產生視覺上的一些變化,因爲Android使用不同的顏色高亮顯示過渡繪製的區域,如果你只在某個像素上繪製了一次,那麼將不會有任何顏色,然而,隨着過度繪製的增加,顏色也會改變.
依據過度繪製的層度可以分成:

  • 無過度繪製(一個像素只被繪製了一次)
  • 過度繪製x1(一個像素被繪製了兩次)
  • 過度繪製x2(一個像素被繪製了三次)
  • 過度繪製x3(一個像素被繪製了四次)
  • 過度繪製x4+(一個像素被繪製了五次以上


    image.png
優化方案
  • 首先,你需要從視圖中刪除對最終呈現的圖像沒有幫助背景和繪圖,因爲這屬於浪費性能.
  • 接下來,你可以定義你知道會隱藏部分視圖的屏幕區域,這有助於降低CPU和GPU開銷
方案演示

上面說了那麼多理論性的內容,光說不練假把式,接下來我們真刀真槍的幹上那麼一干.附上了練習項目的地址,大家可以下載下來也動手試試.
練習項目
現在我們打開應用可以看見這些紅色的過渡繪製的區域,我們的任務就是減少這些過度繪製.

image.png

按照文中之前說的,我們需要先去了解一下UI是如何創建的並且試着做一些清理減少過渡繪製,試着清除不必要的背景和圖片.
分析發現,我們的整體背景現在是藍色過度繪製級別的,而導致過度繪製的原因是在ChatumLatinumActivity中使用了不透明白色背景的佈局填充了整個屏幕,而Android的主題會默認設置顏色.因此就導致了不必要的過度繪製.
image.png

因爲我們可能需要自己設置我們應用的背景顏色,所以就需要將主題中的背景顏色取消,我們使用getWindow().setBackgroundDrawable(null);來取消原來的背景,這個方法的作用就是去除Window也就是DecorView的背景顏色.效果如下.變成了藍色過度繪製級別.
image.png

接下來就可以仔細的去看看其他的XML文件是否仍有可以清除的不必要的背景顏色了.

暫時先整理到這.後續會盡快更新.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章