Android中硬件加速的基本概念及其如何通過(guò)不同的API和布局文件屬性來(lái)提升繪制和動(dòng)畫性能
硬件加速
硬件加速是指利用設(shè)備的硬件資源來(lái)加速圖形渲染和圖像處理等操作,以提高應(yīng)用程序的性能和用戶體驗(yàn)。在Android系統(tǒng)中,硬件加速主要通過(guò)以下幾種方式實(shí)現(xiàn):
- GPU加速:Android系統(tǒng)利用設(shè)備的圖形處理單元(GPU)來(lái)加速圖形渲染。通過(guò)將圖形操作交給GPU處理,可以大大提高圖形渲染的速度和質(zhì)量,減輕CPU的負(fù)擔(dān)。
- 硬件加速繪圖API:Android提供了一系列硬件加速的繪圖API,如OpenGL ES、Vulkan等。這些API可以直接與GPU進(jìn)行交互,實(shí)現(xiàn)高效的圖形渲染和圖像處理。
- 硬件加速的窗口管理:Android系統(tǒng)通過(guò)硬件加速的窗口管理機(jī)制,可以實(shí)現(xiàn)窗口的平滑移動(dòng)、縮放和旋轉(zhuǎn)等操作。這樣可以提高窗口的響應(yīng)速度和用戶體驗(yàn)。
- 硬件加速的動(dòng)畫效果:Android系統(tǒng)提供了一系列硬件加速的動(dòng)畫效果,如屬性動(dòng)畫、過(guò)渡動(dòng)畫等。這些動(dòng)畫效果可以利用GPU的計(jì)算能力,實(shí)現(xiàn)流暢的動(dòng)畫效果。
硬件加速可以通過(guò)利用設(shè)備的硬件資源來(lái)加速圖形渲染和圖像處理等操作,提高應(yīng)用程序的性能和用戶體驗(yàn)。
使用硬件加速優(yōu)點(diǎn):
- 「提高性能和響應(yīng)速度」:利用GPU進(jìn)行圖形渲染和合成,硬件加速可以提高應(yīng)用程序的繪制性能和響應(yīng)速度。
- 「減輕CPU負(fù)擔(dān)」:將圖形操作交給GPU處理,可以減輕CPU的負(fù)擔(dān),使其能夠更高效地處理其他任務(wù)。
- 「提高用戶體驗(yàn)」:通過(guò)優(yōu)化圖形渲染和多媒體處理,硬件加速可以帶來(lái)更加流暢、逼真的用戶體驗(yàn)。
在Android里,硬件加速專指把View中繪制的計(jì)算工作交給GPU來(lái)處理,這個(gè)繪制的計(jì)算工作通常指的是把繪制方法中的那些Canvas.drawXXX()變成實(shí)際的像素操作。
加速原理
在硬件加速關(guān)閉的時(shí)候,Canvas繪制的工作方式是把要繪制的內(nèi)容寫進(jìn)一個(gè)Bitmap,然后在之后的渲染過(guò)程中,這個(gè)Bitmap的像素內(nèi)容被直接用于渲染到屏幕。這種繪制方式的主要計(jì)算工作在于把繪制操作轉(zhuǎn)換為像素的過(guò)程(例如由一句 Canvas.drawCircle() 來(lái)獲得一個(gè)具體的圓的像素信息),這個(gè)過(guò)程的計(jì)算是由CPU來(lái)完成的。大致就像這樣:
圖片
開(kāi)啟硬件加速后,Canvas的工作方式改變了,先把繪制的內(nèi)容轉(zhuǎn)為GPU的操作保存下來(lái),然后交給GPU來(lái)完成顯示工作。大致過(guò)程:
圖片
從上圖可以看出,開(kāi)啟硬件加速后,繪制的計(jì)算工作由CPU交給GPU,不過(guò)這怎么就能起到加速作用,讓繪制變快了呢?硬件加速能夠讓繪制變快,主要有三個(gè)原因:
- 本來(lái)CPU的工作,分?jǐn)傄徊糠纸oGPU,自然可以提高效率。
- 相對(duì)于CPU來(lái)說(shuō),GPU自身的設(shè)計(jì)本來(lái)就對(duì)于很多常見(jiàn)類型內(nèi)容的計(jì)算(例如簡(jiǎn)單的圓形、方形)具有優(yōu)勢(shì)。
- 由于繪制流程的不同;硬件加速在界面內(nèi)容發(fā)生重繪的時(shí)候繪制流程可以得到優(yōu)化,避免一些重復(fù)操作,從而大幅提升繪制效率。
關(guān)閉硬件加速時(shí),繪制內(nèi)容會(huì)被CPU轉(zhuǎn)為實(shí)際的像素直接渲染到屏幕,這個(gè)·[實(shí)際的像素]·是由Bitmap承載的,在界面的某個(gè)View由于內(nèi)容發(fā)生改變而調(diào)用invalidate()方法時(shí),如果沒(méi)有開(kāi)啟硬件加速,為了正確計(jì)算Bitmap的像素,這個(gè)View的父View、父View的父View乃至一直向上知道最頂級(jí)的View,以及所有和它相交的View,都需要被調(diào)用invalidate()來(lái)重繪,一個(gè)View的改變使得大半個(gè)界面甚至整個(gè)界面重繪一遍,這個(gè)工作量是非常大的。
開(kāi)啟硬件加速時(shí),繪制的內(nèi)容會(huì)被轉(zhuǎn)換成GPU的操作保存下來(lái)(承載的形式成為DisplayList,對(duì)應(yīng)的類也叫作DisplayList)轉(zhuǎn)交給GPU。由于所有繪制的內(nèi)容都沒(méi)有變成最終的像素,所以它們之間是相互獨(dú)立的,那么在界面內(nèi)容發(fā)生改變時(shí),只需把發(fā)生了改變的View調(diào)用invalidate()方法以更新它所對(duì)應(yīng)的GPU就好,至于它的父View和兄弟View,只需要保持原樣,那么這個(gè)工作量就很小了。
正是由于上面的原因,硬件加速不僅是由于GPU的引入提高效率,而且因?yàn)槔L制機(jī)制的改變,而極大的提高了界面內(nèi)容改變時(shí)的刷新效率。
硬件加速不止有好處,也會(huì)受到GPU繪制方式的限制,Canvas有些方法在硬件加速開(kāi)啟時(shí)會(huì)失效或者無(wú)法正常工作,比如:開(kāi)啟硬件加速,clipPath()在API18及以上系統(tǒng)中才有效,具體的API限制和API版本的關(guān)系如下圖:
圖片
在開(kāi)發(fā)Android應(yīng)用時(shí),需要考慮到設(shè)備的兼容性和性能差異,合理使用硬件加速功能。
硬件加速開(kāi)啟
- 在AndroidManifest.xml文件中的<application>標(biāo)簽下添加如下屬性:
android:hardwareAccelerated="true"
這將啟用應(yīng)用程序的硬件加速功能。
- 在需要使用硬件加速的Activity的布局文件中,可以使用以下屬性來(lái)啟用硬件加速:
android:hardwareAccelerated="true"
或者在代碼中使用以下方法來(lái)啟用硬件加速:
getWindow().setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
- View繪制開(kāi)啟硬件加速:
//View開(kāi)啟硬件加速
view.setLayerType(LAYER_TYPE_HARDWARE, null);
view.setLayerType(LAYER_TYPE_SOFTWARE, null)方法的作用并不是關(guān)閉硬件加速,當(dāng)它的參數(shù)為L(zhǎng)AYER_TYPE_SOFTWARE的時(shí)候,可以順便把硬件加速關(guān)掉而已;并且除了這個(gè)方法外,Android并沒(méi)有提供專門的View級(jí)別的硬件加速開(kāi)關(guān),所以順便成了一個(gè)開(kāi)關(guān)硬件加速的方法。
setLayerType()方法的作用就是設(shè)置View Layer的類型。ViewLayer又稱為離屏緩沖(off-screen Buffer),作用就是單獨(dú)啟用一塊地方來(lái)繪制View,而不是使用繪制軟件的Bitmap或者通過(guò)硬件加速的GPU,這塊地方可能是一塊單獨(dú)的Bitmap,也可能是一塊OpenGL的紋理(texture,OpenGL的紋理可以簡(jiǎn)單理解為圖像的意思),具體取決于硬件加速是否開(kāi)啟。采取什么來(lái)繪制View不是關(guān)鍵,關(guān)鍵在于當(dāng)設(shè)置了View Layer的時(shí)候,它的繪制會(huì)被緩存下來(lái),而且緩存的是最終的繪制結(jié)果,而不是像硬件加速那樣只是把GPU的操作保存下來(lái)再交給GPU去計(jì)算。通過(guò)這樣更進(jìn)一步的緩存方式,View的重繪效率進(jìn)一步提高了:只要繪制的內(nèi)容沒(méi)變,那么不論是CPU繪制還是GPU繪制,都不用重新計(jì)算,只要用之前緩存的結(jié)果就可以了。
在進(jìn)行移動(dòng)、旋轉(zhuǎn)等(無(wú)需調(diào)用 invalidate())的屬性動(dòng)畫的時(shí)候開(kāi)啟Hardware Layer 將會(huì)極大地提升動(dòng)畫的效率,在動(dòng)畫過(guò)程中View本身并沒(méi)有發(fā)生改變,只是位置或角度改變了,這種改變是可以由GPU通過(guò)簡(jiǎn)單計(jì)算就完成的,并不需要重繪整個(gè)View。所以在動(dòng)畫的過(guò)程中開(kāi)啟Hardware Layer,可以讓本來(lái)就依靠硬件加速而變流暢了的動(dòng)畫變得更加流暢。實(shí)現(xiàn)方式大概是這樣:
view.setLayerType(LAYER_TYPE_HARDWARE, null);
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotationY", 180);
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
view.setLayerType(LAYER_TYPE_NONE, null);
}
});
animator.start();
在對(duì)translationX translationY rotation alpha等無(wú)需調(diào)用invalidate()的屬性做動(dòng)畫的時(shí)候方法才適用,因?yàn)榉椒ū旧砝玫木褪钱?dāng)界面不發(fā)生時(shí),緩存未更新所帶來(lái)的時(shí)間的節(jié)省?!覆贿m用于基于自定義屬性繪制的動(dòng)畫?!?/p>
總結(jié)
硬件加速指使用GPU來(lái)完成繪制的計(jì)算工作,從工作分?jǐn)偤屠L制機(jī)制優(yōu)化兩個(gè)角度提升了繪制速度。
硬件加速可以使用setLayerType()來(lái)關(guān)閉硬件加速,但這個(gè)方法其實(shí)是用來(lái)設(shè)置View Layer的:
- 參數(shù)為L(zhǎng)AYER_TYPE_SOFTWARE時(shí),使用軟件來(lái)繪制View Layer,繪制到一個(gè)Bitmap,并順便關(guān)閉硬件加速;
- 參數(shù)為L(zhǎng)AYER_TYPE_HARDWARE時(shí),使用GPU來(lái)繪制View Layer,繪制到一個(gè)OpenGL texture(如果硬件加速關(guān)閉,那么行為和LAYER_TYPE_SOFTWARE一致);
- 參數(shù)為L(zhǎng)AYER_TYPE_NONE時(shí),關(guān)閉View Layer。
View Layer可以加速無(wú)invalidate()時(shí)的刷新效率,但對(duì)于需要調(diào)用invalidate()的刷新無(wú)法加速。繪制所消耗的實(shí)際時(shí)間是比不使用View Layer時(shí)要高的,所以要慎重使用。