硬件加速的原理
將view的繪制函數(shù)轉(zhuǎn)化成OpenGL中的函數(shù)來完成繪制靶病。
軟件繪制與硬件繪制的區(qū)別
-
軟件繪制
在軟件繪制模式宦搬,view是按照下面兩個步驟進行繪制的:
- 無效化View層次結(jié)構(gòu)
- 繪制View的層次結(jié)構(gòu)
繪制的特點:
當應(yīng)用需要更新它的一部分UI累驮,它會調(diào)用view的invalidate方法刃鳄,無效化消息就會通過各種途徑傳遞到View的層次結(jié)構(gòu)诅炉,然后計算屏幕中需要重繪的區(qū)域(臟區(qū)域)黑滴,android系統(tǒng)還會對View層次結(jié)構(gòu)中臟區(qū)域相交的所有view進行繪制罢荡。
不足:
1. 這個模式在每一次繪制都需要執(zhí)行大量的代碼赡突,比如,如果你的應(yīng)用對一個button調(diào)用invalidate,而這個button坐標在其他view的上方锣夹,那么android系統(tǒng)就會重繪這些view崩溪,即使他們沒有發(fā)生改變,僅僅因為它們處于和button相交的區(qū)域漱受。
2. 由于一個view的繪制可能導致另一個view重繪,因此會引起一些不被注意到的bug骡送。
-
硬件繪制
新的繪制模式包含三個步驟:
- 無效化View的層次結(jié)構(gòu)
- 記錄和更新顯示列表
- 繪制顯示列表
android系統(tǒng)依然使用invalidate和draw函數(shù)來請求屏幕刷新渲染界面昂羡,但實際上繪制的時候是有區(qū)別的,不同于立即執(zhí)行繪制命令摔踱,android系統(tǒng)會先把它們記錄在display list上虐先,這個display lists包含view的層次結(jié)構(gòu)的繪制代碼。其他的優(yōu)化是android系統(tǒng)只需要記錄和更新display lists派敷,通過調(diào)用invalidate函數(shù)來標記那些臟view蛹批,那些沒有被標記為invalidate的view可以簡單的進行重繪通過事先記錄在display list上的記錄。
舉個栗子:
例如篮愉,假設(shè)有一個LinearLayout在Button上面有一個ListView腐芍,那么對于LinearLayout的display list就會像這樣的:
DrawDisplayList(ListView)
DrawDisplayList(Button)
假設(shè)現(xiàn)在你通過調(diào)用setAlpha(0.5)來修改ListView的透明度,那么display list就變成這樣了:
SaveLayerAlpha(0.5)
DrawDisplayList(ListView)
Restore
DrawDisplayList(Button)
關(guān)于ListView的復(fù)雜的繪制代碼并沒有被執(zhí)行潜支,系統(tǒng)只是更新了LinearLayout的display list甸赃,如果應(yīng)用沒有啟用硬件加速,那么listview以及它的父容器LinearLayout的繪制代碼都會再次執(zhí)行冗酿。
硬件加速的優(yōu)勢
流暢性更好:切換到硬件加速埠对,界面固然是更加流暢了络断,但是我們開發(fā)應(yīng)用的時候要想讓GPU的效率更加的高。
性能更好:硬件加速的優(yōu)勢在于display list這個設(shè)計项玛,使用這個的話貌笨,我們就不需要每次重繪都執(zhí)行大量的代碼,因為對臟區(qū)域的襟沮,基于軟件的繪制模式會重繪臟區(qū)域內(nèi)的所有控件锥惋,而display只會更新列表,然后繪制列表內(nèi)的控件开伏。
硬件加速的弊端
- 消耗更多的內(nèi)存:由于要把系統(tǒng)中OpenGL加載到內(nèi)存膀跌,所以O(shè)penGL API調(diào)用就會占用8MB,而實際上會占用更多內(nèi)存固灵,并且使用了硬件必然增加耗電量了捅伤。
- 兼容性:硬件加速是從API 11引入,API 14之后才默認開啟巫玻。對于標準的繪制操作和控件都是支持的丛忆,但是對于自定義View的時候或者一些特殊的繪制函數(shù)就需要考慮是否需要關(guān)閉硬件加速。
tips
-
1.當你的應(yīng)用是硬件加速的仍秤,硬件圖層類型可以傳達更快和更加順滑的動畫熄诡,當你在處理的是一個復(fù)雜的又很多繪制操作的view的時候,運行一個動畫不總是60幀每秒的诗力』烁。可以通過使用硬件層來渲染view到一個硬件的texture中來優(yōu)化這個問題,硬件texture可以用來對view進行動畫姜骡,排除開始動畫的時候需要重繪自己的View导坟,view不會重新重繪除非你改變它的屬性屿良,然后調(diào)用invalidate()圈澈。
如果你運行一個動畫在你的應(yīng)用上,但是得不到一個你想要的順滑結(jié)果尘惧,考慮啟用硬件加速在你的動畫view上康栈。當view從硬件圖層回退的時候,它的一些屬性會通過圖層合成到屏幕上的方式進行處理喷橙,設(shè)置這些屬性將會更加高效啥么,因為它不需要view重繪或者無效化。
因為硬件層消耗video存儲贰逾,所以強烈建議啟用它們只有在動畫時長并且關(guān)閉它們當動畫完成的時候悬荣,你可以完成這個通過使用動畫監(jiān)聽器,這一個比較細節(jié)疙剑,但能夠?qū)iew進行優(yōu)化氯迂,畢竟手機內(nèi)存這么少践叠。
示例代碼應(yīng)該是這樣
View.setLayerType(View.LAYER_TYPE_HARDWARE, null);
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotationY", 180);
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
view.setLayerType(View.LAYER_TYPE_NONE, null);
}
});
animator.start();
-
2. 小心使用alpha屬性
當你使用setAlpha,或者AlphaAnimation嚼蚀,或者ObjectAnimator來改變一個View的透明度時禁灼,它渲染在離屏緩存中需要兩倍填充率,當需要在在一個非常大的view上修改alpha轿曙,就要考慮設(shè)置view的layer type為LAYER_TYPE_HARDWARE弄捕。