Android 4.0硬件加速及繪制技巧
從Android 3.0開始,Android 2D的繪制流程就設(shè)計為能夠更好地支持硬件加速。使用GPU的View在Canvas上進行畫的操作時都會使用硬件加速。在最新的Android版本里,圖形硬件加速及繪制技巧得到了更好的提升.
Android 4.0
1.Android 4.0硬件加速的使用
1.1 硬件加速的控制級別
啟用硬件加速的最簡單方法就是為整個系統(tǒng)打開硬件加速的全局設(shè)置。如果你的程序是標(biāo)準(zhǔn)View或者是Drawable 則硬件加速的全局設(shè)這并不會造成不良的影響。然而硬件加速并不支持所有2D畫的操作,所以開啟硬件加速可能會對使用自定義組件的應(yīng)用程序造成影響,問題常常表現(xiàn)在不可見的元素異常和錯誤的像素渲染,為了解決這個問題Android可以讓你選擇啟動或者禁用以下級別的硬件加速:Application Activity Window 和 View 。
1.1.1 Application級別
在你的Android Manifest文件中添加 屬性標(biāo)記,以便為整個應(yīng)用程序使用硬件加速。
1.1.2 Activity級別
如果你的應(yīng)用程序不能在Application應(yīng)用級別表現(xiàn)良好的話,則可以使用對Activity進行單獨控制。要啟動或者禁用一個Activity的硬件加速,你可以使用activity的android:hardwareAccelerated屬性。下面的一個列子使整個Application啟用硬件加速,但是對一個Activity禁止使用硬件加速。
1.1.3 Window級別
如果你需要更細(xì)粒度的控制,你可以通過如下代碼給window進行加速。
getWindow().setFlags( WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
注意:現(xiàn)階段你不能在Window級別對它禁用硬件加速。
1.1.4 View級別
我們可以對單獨的View在運行時階段禁用硬件加速。我們可以使用如下代碼:
myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
注意:現(xiàn)階段不能夠在View級別進行硬件加速。
1.2 判斷一個View是否已經(jīng)啟用了硬件加速
有時候我們需要知道一個應(yīng)用程序是否已經(jīng)啟用了硬件加速,特別是針對一些自定義控件。因為你的應(yīng)用程序做了很多自定義“畫”的操作,但并不是所有的過程都支持新的“畫”的渲染過程。
有兩種不同的方法來檢查Application是否啟用了硬件加速:
1.2.1 使用View.isHardwareAccelerated() 如果返回true則可以說明這個View所在的窗口已經(jīng)啟用了硬件加速。
1.2.2 Canvas.isHardwareAccelerated() 如果返回true則說明這個Canvas已經(jīng)啟用了硬件加速。
如果你必須要在你的繪畫代碼中進行是否已經(jīng)加速的檢查,如果可能的話請使用Canvas.isHardwareAccelerated()來代替View.isHardwareAccelerated()。當(dāng)一個View是存在于一個已經(jīng)加速的Windows上時,任然可以使用沒有硬件加速的Canvas進行繪畫,這場發(fā)生在,比如,當(dāng)我們把一個View畫到Bitmap上然后用作緩存。
2.Android 4.0的繪制模型
當(dāng)開啟了硬件加速,Android框架將會使用一種新的繪制模型,這種模型將會使用顯示列表把你的應(yīng)用顯示到屏幕上。要完全理解顯示列表和他們?nèi)绾斡绊懩愕膽?yīng)用程序,理解Android 4.0如何在非硬件加速的情況下如何繪制Views是很有必要的,下面將分別介紹軟件加速和硬件加速。
2.1基于軟件的繪制模型
在基于軟件繪制模型中,View的繪制遵循以下兩步:1.使整個控件層級無效。2.對層級進行繪制。
當(dāng)一個應(yīng)用程序需要更新它UI的一部分時,它將會調(diào)用內(nèi)容發(fā)生改變的View的invalidate()方法(或者invalidate的變體)。Invalidate的消息按照View的層級關(guān)系向上傳遞用以計算需要重畫的部分(即臟區(qū)域)。然后Android系統(tǒng)會對和臟區(qū)域有交集的所有View進行繪制,不幸的是這種模型中有兩個缺點:
2.1.1 在這種模型中當(dāng)在不同的層進行畫的時候,會額外執(zhí)行很多代碼。例如一個Button是位于另外一個View之上,當(dāng)對Button調(diào)用 Invalidate()時,Android就會對這個View進行重繪,即便這個View沒有發(fā)生任何變化。
2.1.2 第二個問題是這種繪制模型會隱藏你Application中的Bug。因為Android系統(tǒng)會對和臟區(qū)域有交集的View進行重繪,在這種情況下如果一個view的內(nèi)容發(fā)生了改變,即便這個View的Invalidate()的方法并沒有得到調(diào)用,它也可能被重繪。你便會依賴調(diào)用了invalidate()的其他的控件以便獲得正確的行為,因此每當(dāng)你的Application發(fā)生改變時,這種行為多要隨之發(fā)生改變。也是基于次因,在你的自定義控件中你必須不斷地調(diào)用invalidate()方法,當(dāng)你的數(shù)據(jù)或者是狀態(tài)會影響View的繪制代碼時。
注意:Android的View當(dāng)它們的屬性發(fā)生改變時會自動的調(diào)用Invalidate()。比如,你改變一個 Textview的背景或者是它的文本。
2.2 基于硬件加速模型
Android 系統(tǒng)仍然通過invalidate()和draw()去請求屏幕更新和重新渲染,但是實際處理畫的方式是不同的。不是立即執(zhí)行畫的命令,Android而會將所有畫的命令記錄在一個顯示列表里面,這個顯示列表包含了輸出的View層級的繪制代碼。還有一個優(yōu)化就是Android在顯示列表中只會記錄和更新顯示層級中通過調(diào)用invalidate()函數(shù)被標(biāo)記為“臟”的view。沒有被請求刷新的view可以通過重新請求先前的顯示列表以便重畫。新的繪制模型包括有三個步驟:1.禁用整個View層級。2.記錄和更新顯示列表。3.繪制顯示列表。
使用這個模型你不能依賴一個View和臟區(qū)域有交集就會執(zhí)行draw()方法。要確保Android系統(tǒng)記錄了一個View的顯示列表,你必須調(diào)用invalidate()方法,如果忘記了調(diào)用刷新,會使View即便是發(fā)生了改變后也會看起來相同,這是一個比較容易發(fā)現(xiàn)bug的方式。
使用顯示列表的方式對動畫的表現(xiàn)也是很有好處的,因為設(shè)置指定的屬性值,比如透明度或者旋轉(zhuǎn),就不需要請求刷新目標(biāo)View(這將自動執(zhí)行)。這項優(yōu)化也應(yīng)用于有顯示列表的Views(啟用了硬件加速的View),例如,現(xiàn)在有一個LinearLayout包含了一個ListView和Button,listview在button的上面。這時候LinearLayout的顯示列表如下所示:
◆DrawDisplayList(ListView) ;
◆DrawDisplayList(Button) ;
假設(shè)你現(xiàn)在你想更新這個Listview的不透明度,在設(shè)置Listview的 setAlpha(0.5f) 屬性之后,LinearLayout的顯示列表應(yīng)該包含如下:
◆ SaveLayerAlpha(0.5)
◆ DrawDisplayList(ListView)
◆ Restore
◆ DrawDisplayList(Button)
這時候繪制Listview的復(fù)雜過程就會省略了,取而代之的是簡單的更新了LinearLayout的顯示列表。如果一個應(yīng)用程序并沒有啟用硬件加速,Listview和它的父view的畫的代碼都會重新執(zhí)行。
3.Android 4.0 View的層
3.1層的分類
所有的Android版本都有能力對離屏緩沖進行渲染,或者是使用View的繪制緩沖,或者是使用Canvas.saveLayer()函數(shù)。離屏緩沖或者Layer能夠有很多種應(yīng)用,例如能使處理復(fù)雜view的動畫效果或者應(yīng)用一些合成效果都有更好地表現(xiàn)。例如你可以通過Canvas.saveLayer()的方式來對View做一個漸入漸出效果同時把它渲染到Layer中,然后再加上不透明效果合成后顯示到屏幕上。
由Android 3.0開始你就能夠通過View.setLayerType()方法對何時以及如何使用層有了更多的控制,這個API具有兩個參數(shù)一個是你想使用的層類型,另外一個是可選參數(shù)Paint表明了Layer是如何被疊加的。你可以把Paint參數(shù)應(yīng)用到顏色過濾上,特別是混合模式或者是對一個layer進行不透明效果。一個View可以使用如下的三種layer類型之一:
◆ LAYER_TYPE_NONE: 這個View將被按普通的方式進行渲染,但是不會返回一個離屏的緩沖,這個是默認(rèn)的行為。
◆ LAYER_TYPE_HARDWARE:如果這個應(yīng)用被硬件加速的話,這個View將會在硬件中渲染為硬件紋理,如果應(yīng)用程序并沒有被硬件加速,則其效果和LAYER_TYPE_SOFTWARE是相同的。
◆ LAYER_TYPE_SOFTWARE: 此View 通過軟件渲染為一個bitmap。
3.2 層的使用
使用層的類型取決于你的目的:
3.2.1 性能:使用硬件層來渲染一個View成為硬件紋理。一旦一個View被渲染為一個層,它的繪制代碼將不會得到執(zhí)行,直到你調(diào)用了invalidate()函數(shù)。對于一些動畫,比如透明動畫可以直接應(yīng)用到一個層上,這是GPU最有效率的使用方式。
3.2.2 顯示效果:使用硬件或者軟件層和Paint來對一個View進行特殊的視覺處理,例如你可以對一個View通過使用ColorMatrixColorFilter來實現(xiàn)黑白效果。