Android之硬件加速

????????所謂硬件加速赏寇,指的是把某些計算工作交給專門的硬件來做饼灿,而不是和普通的計算工作一樣交給CPU 來處理悔橄。這樣不僅減輕了 CPU 的壓力绒疗,而且由于有了「專人」的處理侵歇,這份計算工作的速度也被加快了。這就是「硬件加速」吓蘑。

? ??????而對于 Android 來說惕虑,硬件加速有它專屬的意思:在 Android 里,硬件加速專指把View 中繪制的計算工作交給 GPU 來處理磨镶。進一步地再明確一下溃蔫,這個「繪制的計算工作」指的就是把繪制方法中的那些Canvas.drawXXX() 變成實際的像素這件事。

? ? 原理

? ??????在硬件加速關閉的時候琳猫, Canvas 繪制的工作方式是:把要繪制的內容寫進一個Bitmap 伟叛,然后在之后的渲染過程中,這個 Bitmap 的像素內容被直接用于渲染到屏幕脐嫂。這種繪制方式的主要計算工作在于把繪制操作轉換為像素的過程(例如由一句Canvas.drawCircle() 來獲得一個具體的圓的像素信息)痪伦,這個過程的計算是由CPU 來完成的侄榴。大致就像這樣:


????????而在硬件加速開啟時,Canvas 的工作方式改變了:它只是把繪制的內容轉換為GPU 的操作保存了下來网沾,然后就把它交給 GPU,最終由 GPU 來完成實際的顯示工作蕊爵。大致是這樣:


如圖辉哥,在硬件加速開啟時,CPU 做的事只是把繪制工作轉換成 GPU 的操作攒射,這個工作量相對來說是非常小的醋旦。

怎么就「加速」了?

從上面的圖中可以看出会放,硬件加速開啟后饲齐,繪制的計算工作由 CPU 轉交給了GPU。不過這怎么就能起到「加速」作用咧最,讓繪制變快了呢捂人?

硬件加速能夠讓繪制變快,主要有三個原因:

1. 本來由 CPU 自己來做的事矢沿,分攤給了 GPU 一部分滥搭,自然可以提高效率;

2. 相對于 CPU 來說捣鲸,GPU 自身的設計本來就對于很多常見類型內容的計算(例如簡單的圓形瑟匆、簡單的方形)具有優(yōu)勢;

3. 由于繪制流程的不同栽惶,硬件加速在界面內容發(fā)生重繪的時候繪制流程可以得到優(yōu)化愁溜,避免了一些重復操作,從而大幅提升繪制效率外厂。

其中前兩點可以總結為一句:用了 GPU冕象,繪制就是快。原因很直觀酣衷,不再多說交惯。

關于第三點,它的原理我大致說一下:

????????前面說到穿仪,在硬件加速關閉時席爽,繪制內容會被 CPU 轉換成實際的像素,然后直接渲 染到屏幕啊片。具體來說只锻,這個「實際的像素」,它是由 Bitmap 來承載的紫谷。在界面中的某個 View 由于內容發(fā)生改變而調用 invalidate() 方法時齐饮,如果沒有開啟硬件加速捐寥,那么為了正確計算 Bitmap 的像素,這個 View 的父 View祖驱、父 View 的父View 乃至一直向上直到最頂級 View握恳,以及所有和它相交的兄弟 View ,都需要被調用 invalidate() 來重繪捺僻。一個 View 的改變使得大半個界面甚至整個界面都重繪一遍乡洼,這個工作量是非常大的。

?? ? ? ?而在硬件加速開啟時匕坯,前面說過束昵,繪制的內容會被轉換成 GPU 的操作保存下來(承載的形式稱為 display list,對應的類也叫做 DisplayList )葛峻,再轉交給GPU锹雏。由于所有的繪制內容都沒有變成最終的像素,所以它們之間是相互獨立的术奖,那么在界面內容發(fā)生改變的時候礁遵,只要把發(fā)生了改變的 View 調用 invalidate()方法以更新它所對應的 GPU 操作就好,至于它的父 View 和兄弟 View腰耙,只需要保持原樣榛丢。那么這個工作量就很小了。

正是由于上面的原因挺庞,硬件加速不僅是由于 GPU 的引入而提高了繪制效率晰赞,還由于繪制機制的改變,而極大地提高了界面內容改變時的刷新效率选侨。

限制

如果僅僅是這樣掖鱼,硬件加速只有好處沒有缺陷,那大家都不必關心硬件加速了援制,這?篇文章也不會出現(xiàn):既然是好東西就用唄戏挡,關心那么多原理干嗎?

可事實就是晨仑,硬件加速不只是好處褐墅,也有它的限制:受到 GPU 繪制方式的限制, Canvas 的有些方法在硬件加速開啟式會失效或無法正常工作洪己。比如妥凳,在硬件加速開啟時, clipPath() 在 API 18 及以上的系統(tǒng)中才有效答捕。具體的 API 限制和API 版本的關系如下圖:



????????所以逝钥,如果你的自定義控件中有自定義繪制的內容,最好參照一下這份表格拱镐,確保你的繪制操作可以正確地在所有用戶的手機里能夠正常顯示艘款,而不是只在你的運行了最新版本 Android 系統(tǒng)的 Nexus 或 Pixel 里測試一遍沒問題就發(fā)布了持际,小心被祭天。不過有一點可以放心的是哗咆,所有的原生自帶控件蜘欲,都沒有用到 API 版本不兼容的繪制操作,可以放心使用岳枷。所以你只要檢查你寫的自定義繪制就好芒填。

View Layer

如果你的繪制操作不支持硬件加速,你需要手動關閉硬件加速來繪制界面空繁,關閉的方式是通過這行代碼:

view.setLayerType(LAYER_TYPE_SOFTWARE, null);?

有不少人都有過疑問:什么是 layer type?如果這個方法是硬件加速的開關朱庆,那么它 的參數(shù)為什么不是一個 LAYER_TYPE_SOFTWARE 來關閉硬件加速以及一個LAYER_TYPE_HARDWARE 來打開硬件加速這么兩個參數(shù)盛泡,而是三個參數(shù),在SOFTWARE 和 HARDWARE 之外還有一個 LAYER_TYPE_NONE 娱颊?難道還能既不用軟件繪制傲诵,也不用硬件繪制嗎?

事實上箱硕,這個方法的本來作用并不是用來開關硬件加速的拴竹,只是當它的參數(shù)為LAYER_TYPE_SOFTWARE 的時候,可以「順便」把硬件加速關掉而已剧罩;并且除了這個方法之外栓拜,Android 并沒有提供專門的 View 級別的硬件加速開關,所以它就「順便」成了一個開關硬件加速的方法惠昔。setLayerType() 這個方法幕与,它的作用其實就是名字里的意思:設置 View Layer 的類型。所謂 View Layer镇防,又稱為離屏緩沖(Off-screen Buffer)啦鸣,它的作用是單獨啟用一塊地方來繪制這個 View ,而不是使用軟件繪制的 Bitmap 或者通過硬件加速的 GPU来氧。這塊「地方」可能是一塊單獨的 Bitmap 诫给,也可能是一塊 OpenGL 的紋理(texture,OpenGL 的紋理可以簡單理解為圖像的意思)啦扬,具體取決于硬件加速是否開啟中狂。

采用什么來繪制 View 不是關鍵,關鍵在于當設置了 View Layer 的時候考传,它的繪制會被緩存下來吃型,而且緩存的是最終的繪制結果,而不是像硬件加速那樣只是把 GPU 的操作保存下來再交給 GPU 去計算僚楞。通過這樣更進一步的緩存方式勤晚,View 的重繪效率進一步提高了:只要繪制的內容沒有變枉层,那么不論是 CPU 繪制還是 GPU 繪制,它們都不用重新計算赐写,而只要只用之前緩存的繪制結果就可以了鸟蜡。

基于這樣的原理,在進行移動挺邀、旋轉等(無需調用 invalidate() )的屬性動畫的 時候開啟 Hardware Layer 將會極大地提升動畫的效率揉忘,因為在動畫過程中 View 本身并沒有發(fā)生改變,只是它的位置或角度改變了端铛,而這種改變是可以由 GPU 通過簡單計算就完成的泣矛,并不需要重繪整個 View。所以在這種動畫的過程中開啟Hardware Layer禾蚕,可以讓本來就依靠硬件加速而變流暢了的動畫變得更加流暢您朽。實現(xiàn)方式大概是這樣:


或者如果是使用 ViewPropertyAnimator ,那么更簡單:


不過一定要注意换淆,只有你在對 translationX translationY rotation alpha 等無需調用 invalidate() 的屬性做動畫的時候哗总,這種方法才適用,因為這種方法本身利用的就是當界面不發(fā)生時倍试,緩存未更新所帶來的時間的節(jié)省讯屈。所以簡單地說——

這種方式不適用于基于自定義屬性繪制的動畫。一定記得這句話县习。一定記得這句話涮母。一定記得這句話。

總結

硬件加速指的是使用 GPU 來完成繪制的計算工作准颓,代替 CPU哈蝇。它從工作分攤和繪 制機制優(yōu)化這兩個角度提升了繪制的速度。

硬件加速可以使用 setLayerType() 來關閉硬件加速攘已,但這個方法其實是用來設置View Layer 的:

1. 參數(shù)為 LAYER_TYPE_SOFTWARE 時炮赦,使用軟件來繪制 View Layer,繪制到一個Bitmap样勃,并順便關閉硬件加速吠勘;

2. 參數(shù)為 LAYER_TYPE_HARDWARE 時,使用 GPU 來繪制 View Layer峡眶,繪制到一個OpenGL texture(如果硬件加速關閉剧防,那么行為和 VIEW_TYPE_SOFTWARE 一致);

3. 參數(shù)為 LAYER_TYPE_NONE 時辫樱,關閉 View Layer峭拘。View Layer 可以加速無 invalidate() 時的刷新效率,但對于需要調用invalidate() 的刷新無法加速。

View Layer 繪制所消耗的實際時間是比 不使用 View Layer 時要高的鸡挠,所以要慎重使用辉饱。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市拣展,隨后出現(xiàn)的幾起案子彭沼,更是在濱河造成了極大的恐慌,老刑警劉巖备埃,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件姓惑,死亡現(xiàn)場離奇詭異,居然都是意外死亡按脚,警方通過查閱死者的電腦和手機于毙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來辅搬,“玉大人望众,你說我怎么就攤上這事∩⌒粒” “怎么了?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵夯缺,是天一觀的道長蚤氏。 經常有香客問我,道長踊兜,這世上最難降的妖魔是什么竿滨? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮捏境,結果婚禮上于游,老公的妹妹穿的比我還像新娘。我一直安慰自己垫言,他們只是感情好贰剥,可當我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著筷频,像睡著了一般蚌成。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上凛捏,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天担忧,我揣著相機與錄音,去河邊找鬼坯癣。 笑死瓶盛,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播惩猫,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼芝硬,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了帆锋?” 一聲冷哼從身側響起吵取,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎锯厢,沒想到半個月后皮官,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡实辑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年捺氢,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片剪撬。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡摄乒,死狀恐怖,靈堂內的尸體忽然破棺而出残黑,到底是詐尸還是另有隱情馍佑,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布梨水,位于F島的核電站拭荤,受9級特大地震影響,放射性物質發(fā)生泄漏疫诽。R本人自食惡果不足惜舅世,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望奇徒。 院中可真熱鬧雏亚,春花似錦、人聲如沸摩钙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽腺律。三九已至奕短,卻和暖如春匀钧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背之斯。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留酿炸,地道東北人涨冀。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像扁眯,于是被迫代替她去往敵國和親翅帜。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,047評論 2 355

推薦閱讀更多精彩內容