最近項(xiàng)目中遇到了因?yàn)橛布铀僖鸬囊恍﹩栴},故這里深入學(xué)習(xí)了解一下關(guān)于硬件加速的一些東西
背景
什么是硬件加速丝里?
硬件加速是Android系統(tǒng)在繪制圖形時采取的一種方式犬金。
圖形的繪制,本質(zhì)上就是界面的渲染。在渲染界面的時候刻恭,是要經(jīng)過一系列計(jì)算的,這部分計(jì)算通常是邏輯較簡單扯夭,但數(shù)據(jù)量龐大的浮點(diǎn)運(yùn)算鳍贾。
在操作系統(tǒng)層面,有一個東西叫中央處理器——CPU交洗,他是計(jì)算機(jī)設(shè)備的核心器件之一骑科,主要功能是解釋計(jì)算機(jī)指令以及處理計(jì)算機(jī)軟件中的數(shù)據(jù)。除此之外构拳,計(jì)算機(jī)還有一個器件咆爽,叫做圖形處理器——GPU,他類似于CPU置森,但是是專門為運(yùn)行繪圖運(yùn)算的微處理器斗埂。
那么CPU和GPU的區(qū)別在哪里呢?
- CPU內(nèi)部算數(shù)邏輯單元(ALU)較少凫海,控制器較復(fù)雜呛凶,適合進(jìn)行復(fù)雜的邏輯運(yùn)算
- GPU控制器簡單,但是包含了較多的算數(shù)邏輯單元行贪,可并行運(yùn)行大量計(jì)算
結(jié)果顯而易見漾稀,因?yàn)榻缑驿秩镜挠?jì)算是邏輯簡單但是數(shù)據(jù)量很大的浮點(diǎn)運(yùn)算,所以如果使用CPU來對界面渲染做運(yùn)算建瘫,效果自然比不了GPU崭捍。
所以,硬件加速繪制圖形是一般會采用的軟件繪制就是由CPU來繪制的啰脚。硬件加速缕贡,就是通過底層代碼,將CPU中一部分不擅長的圖形計(jì)算轉(zhuǎn)換成GPU專用指令,然后交給GPU來完成晾咪。而對于Android來講收擦,硬件加速就是將View的繪制工作從原來的CPU轉(zhuǎn)交給GPU來做。
原理
硬件繪制之所以比軟件繪制“快速”谍倦,除了如上所述的獎一部分計(jì)算量交給更適合的硬件來做外塞赂,還有一個很重要的原因在于繪制區(qū)域即繪制內(nèi)容的選擇不一樣。
在關(guān)閉了硬件加速昼蛀,即采用軟件繪制時宴猾,繪制區(qū)域是這樣獲取的:從要執(zhí)行 invalidate()
方法的View開始,遍歷從跟View開始的整個View結(jié)構(gòu)叼旋,標(biāo)記出需要重新繪制的 臟區(qū)域
仇哆。在這個過程中,除了我們直接修改的View需要繪制外夫植,其他的所有View讹剔,都可能因?yàn)檎谏w、相交等原因详民,被標(biāo)記為需要繪制延欠,這樣一來繪制的區(qū)域就會變的很大。這樣一來一旦開始繪制沈跨,搞不好會有很多“無辜”的View也被重新繪制由捎,雖然這些View未必真的需要被重繪。
而采用硬件加速時饿凛,就完全不一樣了狞玛。硬件繪制,首先將View抽象為 RenderNode
節(jié)點(diǎn)涧窒,將對View的繪制心肪,抽象為 DrawOp
,每個View不僅持有自己的繪制操作 DrawOp
組成的List杀狡,還持有其子View的繪制入口蒙畴,而 DrawOp
中保存有對應(yīng)的 OpenGL 繪制命令,這樣便形成了一個完整的樹狀結(jié)構(gòu)呜象。其次膳凝,硬件繪制是直接交給一個Render線程來執(zhí)行繪制的,而不是主線程恭陡,這樣也緩解了主線程的部分壓力蹬音。最后,在進(jìn)行實(shí)際繪制時休玩,每個View的實(shí)際繪制操作對應(yīng)于 DrawOp
著淆,在繪制時只需更新其中保存的繪制命令劫狠,即可完成這個View單獨(dú)的繪制,而不會影響到其他View永部。
問題
雖然硬件加速有很多優(yōu)點(diǎn)独泞,但是也有許多坑。
首先苔埋,一些Api方法是不支持硬件加速的懦砂。其次,在使用Webview時组橄,如果啟用了硬件加速荞膘,那么有時會出現(xiàn)花屏、閃爍等異常狀況玉工。
最后羽资,正如前面說的,由于不支持一些Api遵班,所以在做自定義View時屠升,有可能因?yàn)殚_啟硬件加速導(dǎo)致View的繪制效果不理想。
如何使用
一開始Android是默認(rèn)關(guān)閉硬件加速的费奸。從Android4.0版本開始弥激,默認(rèn)是開啟了硬件加速的进陡。硬件加速固然有很多優(yōu)點(diǎn)愿阐,但是由于種種原因(系統(tǒng)設(shè)計(jì)、歷史遺留趾疚、以及自身的局限性)導(dǎo)致在有些情況會出現(xiàn)一些問題缨历,這個時候又需要我們手動關(guān)閉了。
硬件加速的開關(guān)分為四個級別糙麦,分別為App級別辛孵、Activity級別、Window級別以及View級別赡磅。
- App級別:直接在
AndroidManifest.xml
文件中魄缚,<application>
標(biāo)簽下加入一個屬性,屬性值為true
為開啟焚廊,false
為關(guān)閉:
<application android:hardwareAccelerated="true">
- Activity級別:類似于App級別冶匹,在
<activity>
標(biāo)簽下加入同樣的屬性:
<activity android:hardwareAccelerated="true">
- Window級別: 在Window級別,只能通過Java代碼形式動態(tài)的開啟硬件加速而不能關(guān)閉:
getWindow().setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
- View級別:View層比較特殊咆瘟,這里只允許關(guān)閉硬件加速嚼隘,而無法開啟。而且相關(guān)的接口并不是專門用來做硬件加速開關(guān)的袒餐,而是在給View設(shè)置Layer時“順便”關(guān)閉了硬件加速:
view.setLayerType(LAYER_TYPE_SOFTWARE, null);
這個方法只是給View設(shè)置了一個LayerType飞蛹,而且參數(shù)有三種:LAYER_TYPE_SOFTWARE LAYER_TYPE_HARDWARE LAYER_TYPE_NONE谤狡,這是什么意思呢?關(guān)于這一部分卧檐,在官網(wǎng)中有詳細(xì)的解釋:
You currently cannot enable hardware acceleration at the view level. View layers have other functions besides disabling hardware acceleration. See View layers for more information about their uses.
官方說在View層只能關(guān)閉墓懂,不能開啟,至于為什么霉囚,引用一段扔物線大佬的解釋:
setLayerType() 這個方法拒贱,它的作用其實(shí)就是名字里的意思:設(shè)置 View Layer 的類型。所謂 View Layer佛嬉,又稱為離屏緩沖(Off-screen Buffer)逻澳,它的作用是單獨(dú)啟用一塊地方來繪制這個 View ,而不是使用軟件繪制的 Bitmap 或者通過硬件加速的 GPU暖呕。這塊「地方」可能是一塊單獨(dú)的 Bitmap斜做,也可能是一塊 OpenGL 的紋理(texture,OpenGL 的紋理可以簡單理解為圖像的意思)湾揽,具體取決于硬件加速是否開啟瓤逼。采用什么來繪制 View 不是關(guān)鍵,關(guān)鍵在于當(dāng)設(shè)置了 View Layer 的時候库物,它的繪制會被緩存下來霸旗,而且緩存的是最終的繪制結(jié)果,而不是像硬件加速那樣只是把 GPU 的操作保存下來再交給 GPU 去計(jì)算戚揭。通過這樣更進(jìn)一步的緩存方式诱告,View 的重繪效率進(jìn)一步提高了:只要繪制的內(nèi)容沒有變,那么不論是 CPU 繪制還是 GPU 繪制民晒,它們都不用重新計(jì)算精居,而只要只用之前緩存的繪制結(jié)果就可以了。
所以潜必,如果給View設(shè)置了Layer靴姿,且值為SOFTWARE,那么就是用軟件來做View Layer磁滚,自然就關(guān)閉了硬件加速佛吓。而如果硬件加速已經(jīng)關(guān)閉,參數(shù)HARDWARE的作用跟SOFTWARE一樣垂攘,自然也無法開啟硬件加速维雇。而值為NONE時,直接就關(guān)閉了ViewLayer搜贤,所以在View層只能關(guān)閉谆沃、不能開啟,正如官方文檔所說:
- LAYER_TYPE_NONE: The view is rendered normally and is not backed by an off-screen buffer. This is the default behavior.
- LAYER_TYPE_HARDWARE: The view is rendered in hardware into a hardware texture if the application is hardware accelerated. If the application is not hardware accelerated, this layer type behaves the same as LAYER_TYPE_SOFTWARE.
- LAYER_TYPE_SOFTWARE: The view is rendered in software into a bitmap.