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