本文的主要內容來自SDK文章的"Hardware
Acceleration”.
從Android 3.0開始,Android的2D渲染管線可以更好的支援硬體加速。硬體加速使用GPU進行View上的繪製操作。
硬體加速可以在一下四個層級開啟或關閉:
- Application
- Activity
- Window
- View
Application層級
往您的應用程式AndroidManifest.xml檔案為application標籤添加如下的屬性即可為整個應用程式開啟硬體加速:
<application android:hardwareAccelerated="true" ...>
Activity層級
您還可以控制每個activity是否開啟硬體加速,只需在activity元素中添加android:hardwareAccelerated屬性即可辦到。比如下面的例子,在application層級開啟硬體加速,但在某個activity上關閉硬體加速。
<application android:hardwareAccelerated="true"> <activity ... /> <activity android:hardwareAccelerated="false" /></application>
Window層級
如果您需要更小粒度的控制,可以使用如下代碼開啟某個window的硬體加速:
getWindow().setFlags( WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
註:目前還不能在window層級關閉硬體加速。
View層級
您可以在運行時用以下的代碼關閉單個view的硬體加速:
myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
註:您不能在view層級開啟硬體加速
為什麼需要這麼多層級的控制?
很明顯,硬體加速能夠帶來效能提升,android為什麼要弄出這麼多層級的控制,而不是預設就是全部硬體加速呢?原因是並非所有的2D繪圖操作支援硬體加速,如果您的程式中使用了自訂視圖或者繪圖調用,程式可能會工作不正常。如果您的程式中只是用了標準的視圖和Drawable,放心大膽的開啟硬體加速吧!具體是哪些繪圖操作不支援硬體加速呢?以下是已知不支援硬體加速的繪圖操作:
- Canvas
- clipPath()
- clipRegion()
- drawPicture()
- drawPosText()
- drawTextOnPath()
- drawVertices()
- Paint
- setLinearText()
- setMaskFilter()
- setRasterizer()
另外還有一些繪圖操作,開啟和不開啟硬體加速,效果不一樣:
- Canvas
- clipRect():
XOR, Difference和ReverseDifference裁剪模式被忽略,3D變換將不會應用在裁剪的矩形上。
- drawBitmapMesh():colors數組被忽略
- drawLines():反鋸齒不支援
- setDrawFilter():可以設定,但無效果
- Paint
- setDither(): 忽略
- setFilterBitmap():過濾永遠開啟
- setShadowLayer():只能用在文本上
- ComposeShader
- ComposeShader只能包含不同類型的shader (比如一個BitmapShader和一個LinearGradient,但不能是兩個BitmapShader執行個體)
- ComposeShader不能包含ComposeShader
如果應用程式受到這些影響,您可以在受影響的部分調用setLayerType(View.LAYER_TYPE_SOFTWARE,
null),這樣在其它地方仍然可以享受硬體加速帶來的好處
Android的繪製模型
開啟硬體加速後,Android架構將採用新的繪製模型。基於軟體的繪製模型和基於硬體的繪製模型有和不同呢?
基於軟體的繪製模型
在軟體繪製模型下,視圖按照如下兩個步驟繪製:
1. Invalidate the hierarchy(註:hierarchy怎麼翻譯?)
2. Draw the hierarchy
應用程式調用invalidate()更新UI的某一部分,失效(invalidation)訊息將會在整個視圖層中傳遞,計算每個需要重繪的地區(即髒地區)。然後Android系統將會重繪所有和髒地區有交集的view。很明顯,這種繪圖模式存在缺點:
1. 每個繪製操作中會執行不必要的代碼。比如如果應用程式調用invalidate()重繪button,而button又位於另一個view之上,即使該view沒有變化,也會進行重繪。
2. 可能會掩蓋一些應用程式的bug。因為android系統會重繪與髒地區有交集的view,所以view的內容可能會在沒有調用invalidate()的情況下重繪。這可能會導致一個view依賴於其它view的失效才得到正確的行為。
基於硬體的繪製模型
Android系統仍然使用invalidate()和draw()來繪製view,但在處理繪製上有所不同。Android系統記錄繪製命令到顯示列表,而不是立即執行繪製命令。另一個最佳化就是Android系統只需記錄和更新標記為髒(通過invalidate())的view。新的繪製模型包含三個步驟:
1. Invalidate the hierarchy
2. 記錄和更新顯示列表
3. 繪製顯示列表