當前位置: 首頁IT技術 → Android 4.0硬件加速及繪制技巧

Android 4.0硬件加速及繪制技巧

更多

  從Android 3.0開始,Android 2D的繪制流程就設計為能夠更好地支持硬件加速。使用GPU的View在Canvas上進行畫的操作時都會使用硬件加速。在最新的Android版本里,圖形硬件加速及繪制技巧得到了更好的提升.

 

Android 4.0

  Android 4.0

  1.Android 4.0硬件加速的使用

  1.1 硬件加速的控制級別

  啟用硬件加速的最簡單方法就是為整個系統(tǒng)打開硬件加速的全局設置。如果你的程序是標準View或者是Drawable 則硬件加速的全局設這并不會造成不良的影響。然而硬件加速并不支持所有2D畫的操作,所以開啟硬件加速可能會對使用自定義組件的應用程序造成影響,問題常常表現(xiàn)在不可見的元素異常和錯誤的像素渲染,為了解決這個問題Android可以讓你選擇啟動或者禁用以下級別的硬件加速:Application Activity Window 和 View 。

  1.1.1 Application級別

  在你的Android Manifest文件中添加 屬性標記,以便為整個應用程序使用硬件加速。

  1.1.2 Activity級別

  如果你的應用程序不能在Application應用級別表現(xiàn)良好的話,則可以使用對Activity進行單獨控制。要啟動或者禁用一個Activity的硬件加速,你可以使用activity的android:hardwareAccelerated屬性。下面的一個列子使整個Application啟用硬件加速,但是對一個Activity禁止使用硬件加速。

  1.1.3 Window級別

  如果你需要更細粒度的控制,你可以通過如下代碼給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)啟用了硬件加速

  有時候我們需要知道一個應用程序是否已經(jī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()。當一個View是存在于一個已經(jīng)加速的Windows上時,任然可以使用沒有硬件加速的Canvas進行繪畫,這場發(fā)生在,比如,當我們把一個View畫到Bitmap上然后用作緩存。

   2.Android 4.0的繪制模型

  當開啟了硬件加速,Android框架將會使用一種新的繪制模型,這種模型將會使用顯示列表把你的應用顯示到屏幕上。要完全理解顯示列表和他們如何影響你的應用程序,理解Android 4.0如何在非硬件加速的情況下如何繪制Views是很有必要的,下面將分別介紹軟件加速和硬件加速。

  2.1基于軟件的繪制模型

  在基于軟件繪制模型中,View的繪制遵循以下兩步:1.使整個控件層級無效。2.對層級進行繪制。

  當一個應用程序需要更新它UI的一部分時,它將會調用內容發(fā)生改變的View的invalidate()方法(或者invalidate的變體)。Invalidate的消息按照View的層級關系向上傳遞用以計算需要重畫的部分(即臟區(qū)域)。然后Android系統(tǒng)會對和臟區(qū)域有交集的所有View進行繪制,不幸的是這種模型中有兩個缺點:

  2.1.1 在這種模型中當在不同的層進行畫的時候,會額外執(zhí)行很多代碼。例如一個Button是位于另外一個View之上,當對Button調用 Invalidate()時,Android就會對這個View進行重繪,即便這個View沒有發(fā)生任何變化。

  2.1.2 第二個問題是這種繪制模型會隱藏你Application中的Bug。因為Android系統(tǒng)會對和臟區(qū)域有交集的View進行重繪,在這種情況下如果一個view的內容發(fā)生了改變,即便這個View的Invalidate()的方法并沒有得到調用,它也可能被重繪。你便會依賴調用了invalidate()的其他的控件以便獲得正確的行為,因此每當你的Application發(fā)生改變時,這種行為多要隨之發(fā)生改變。也是基于次因,在你的自定義控件中你必須不斷地調用invalidate()方法,當你的數(shù)據(jù)或者是狀態(tài)會影響View的繪制代碼時。

  注意:Android的View當它們的屬性發(fā)生改變時會自動的調用Invalidate()。比如,你改變一個 Textview的背景或者是它的文本。

  2.2 基于硬件加速模型

  Android 系統(tǒng)仍然通過invalidate()和draw()去請求屏幕更新和重新渲染,但是實際處理畫的方式是不同的。不是立即執(zhí)行畫的命令,Android而會將所有畫的命令記錄在一個顯示列表里面,這個顯示列表包含了輸出的View層級的繪制代碼。還有一個優(yōu)化就是Android在顯示列表中只會記錄和更新顯示層級中通過調用invalidate()函數(shù)被標記為“臟”的view。沒有被請求刷新的view可以通過重新請求先前的顯示列表以便重畫。新的繪制模型包括有三個步驟:1.禁用整個View層級。2.記錄和更新顯示列表。3.繪制顯示列表。

  使用這個模型你不能依賴一個View和臟區(qū)域有交集就會執(zhí)行draw()方法。要確保Android系統(tǒng)記錄了一個View的顯示列表,你必須調用invalidate()方法,如果忘記了調用刷新,會使View即便是發(fā)生了改變后也會看起來相同,這是一個比較容易發(fā)現(xiàn)bug的方式。

  使用顯示列表的方式對動畫的表現(xiàn)也是很有好處的,因為設置指定的屬性值,比如透明度或者旋轉,就不需要請求刷新目標View(這將自動執(zhí)行)。這項優(yōu)化也應用于有顯示列表的Views(啟用了硬件加速的View),例如,現(xiàn)在有一個LinearLayout包含了一個ListView和Button,listview在button的上面。這時候LinearLayout的顯示列表如下所示:

  ◆DrawDisplayList(ListView) ;

  ◆DrawDisplayList(Button) ;

  假設你現(xiàn)在你想更新這個Listview的不透明度,在設置Listview的 setAlpha(0.5f) 屬性之后,LinearLayout的顯示列表應該包含如下:

  ◆ SaveLayerAlpha(0.5)

  ◆ DrawDisplayList(ListView)

  ◆ Restore

  ◆ DrawDisplayList(Button)

  這時候繪制Listview的復雜過程就會省略了,取而代之的是簡單的更新了LinearLayout的顯示列表。如果一個應用程序并沒有啟用硬件加速,Listview和它的父view的畫的代碼都會重新執(zhí)行。

  3.Android 4.0 View的層

  3.1層的分類

  所有的Android版本都有能力對離屏緩沖進行渲染,或者是使用View的繪制緩沖,或者是使用Canvas.saveLayer()函數(shù)。離屏緩沖或者Layer能夠有很多種應用,例如能使處理復雜view的動畫效果或者應用一些合成效果都有更好地表現(xiàn)。例如你可以通過Canvas.saveLayer()的方式來對View做一個漸入漸出效果同時把它渲染到Layer中,然后再加上不透明效果合成后顯示到屏幕上。

  由Android 3.0開始你就能夠通過View.setLayerType()方法對何時以及如何使用層有了更多的控制,這個API具有兩個參數(shù)一個是你想使用的層類型,另外一個是可選參數(shù)Paint表明了Layer是如何被疊加的。你可以把Paint參數(shù)應用到顏色過濾上,特別是混合模式或者是對一個layer進行不透明效果。一個View可以使用如下的三種layer類型之一:

  ◆ LAYER_TYPE_NONE: 這個View將被按普通的方式進行渲染,但是不會返回一個離屏的緩沖,這個是默認的行為。

  ◆ LAYER_TYPE_HARDWARE:如果這個應用被硬件加速的話,這個View將會在硬件中渲染為硬件紋理,如果應用程序并沒有被硬件加速,則其效果和LAYER_TYPE_SOFTWARE是相同的。

  ◆ LAYER_TYPE_SOFTWARE: 此View 通過軟件渲染為一個bitmap。

  3.2 層的使用

  使用層的類型取決于你的目的:

  3.2.1 性能:使用硬件層來渲染一個View成為硬件紋理。一旦一個View被渲染為一個層,它的繪制代碼將不會得到執(zhí)行,直到你調用了invalidate()函數(shù)。對于一些動畫,比如透明動畫可以直接應用到一個層上,這是GPU最有效率的使用方式。

  3.2.2 顯示效果:使用硬件或者軟件層和Paint來對一個View進行特殊的視覺處理,例如你可以對一個View通過使用ColorMatrixColorFilter來實現(xiàn)黑白效果。

  3.2.3 兼容性:使用軟件層類型會強制使一個view在軟件中被渲染。如果一個view是硬件加速的話(比如你設置整個應用程序是硬件加速的話),同時有渲染的問題,這是一種很簡單的方式來限制硬件繪制流程。

  3.3 View的層和動畫的關系

  當你的應用程序已經(jīng)使用了硬件加速的話,硬件層能夠帶來更為快速和更為平滑的動畫效果。當對一個復雜的View進行動畫操作時,因為要進行很多的畫操作,所以并不可能總是能達到60幀每秒。在這種情況下可以通過硬件層來渲染為硬件紋理來提高性能。硬件紋理操作可以用作對一個view進行動畫操作,當進行動畫的時候可以減少對View自身頻繁的重繪。除非你改變這個view的屬性(調用invalidate()方法)或者你手動的調用invalidate()。如果在你的應用中運行一個動畫,但是并沒有得到你想要的平滑效果,可以考慮為你要動畫的view開啟硬件層。

  當一個View通過硬件層返回時,當所有的層疊加后最終的畫面顯示在屏幕時,View一些屬性會被同時被處理。設置這些屬性是十分有效率的,因為他們不需要View去invalidate和重繪。如下的屬性將影響層的疊加,設置這些屬性將會使View自動請求刷新,而且不需要對View進行重繪。

  ◆alpha: 改變層的透明度。

  ◆x, y, translationX, translationY: 改變層的位置

  ◆scaleX, scaleY: 改變層的大小

  ◆rotation, rotationX, rotationY:在3D空間內改變層的方向

  ◆pivotX, pivotY: 指定它進行變形的原點位置

  這些屬性是通過ObjectAnimator對象對一個view進行動畫操作時所使用的,如果你想訪問這些屬性,直接調用這些屬性的setter或者getter方法,例如想改變View的alpha則直接調用setAlpha()。如下的代碼片段顯示了一個View通過Y軸進行3D旋轉。

  view.setLayerType(View.LAYER_TYPE_HARDWARE, null); ObjectAnimator.ofFloat(view, "rotationY", 180).start();

  因為硬件層會消耗視頻的內存,強烈的推薦你在作動畫的時候啟用他們,當動畫完成了之后禁用他們,你可以通過動畫監(jiān)聽來完成這些。代碼如下:

  View.setLayerType(View.LAYER_TYPE_HARDWARE, null); ObjectAnimator animator= ObjectAnimator.ofFloat(view, "rotationY", 180); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { view.setLayerType(View.LAYER_TYPE_NONE, null); } }); animator.start();

  Android 4.0提示和技巧

  切換到硬件加速2D圖形可以立即增強表現(xiàn),但是你還是需要通過如下的建議來設計你的應用程序來更有效率的使用GPU。

  4.1 減少你程序中使用View的數(shù)量

  你系統(tǒng)中畫的view的數(shù)量越多,你的程序就會越慢,在軟件繪制的流程也是一樣的,減少view的數(shù)量是優(yōu)化你UI的一個最簡單的方法。

  4.2 避免過多繪制

  不要過多的疊加層,當一個View被其他view完全遮擋住了的話,最好把被遮擋的view移除掉。如果你需要繪制不同的層做一個疊加效果的話,考慮把這些層合并為一個層。就現(xiàn)在的硬件來看,有一個好的經(jīng)驗就是動畫的每幀不要繪制多余屏幕像素2.5倍的像素數(shù)量(bimap中的透明像素也計算在內)。

  4.3 不要在繪制的方法中創(chuàng)建繪制對象

  一個常見的錯誤就是當繪制方法被調用的時候,每次都要創(chuàng)建一個新的Paint或者Path。這將迫使垃圾回收器過于頻繁的運行,這將對緩沖和硬件的繪制造成影響。

  4.4 不要過于頻繁的修改形狀

  以復雜的shapes,path和旋轉為例,這些繪制都會用到紋理的遮罩。每當你創(chuàng)建或者修改一個path,硬件渲染過程都會創(chuàng)建一個新的遮罩,這耗費的代價是相當大的。

  4.5 不要過于頻繁的修改bitmap

  每當修改一次bitmap的內容,當你下次再繪制它的時候都會以GPU的紋理形式上傳一次。

  4.6 要小心使用alpha通道

  當你使用setAlpha ,AlphaAnimation或者ObjectAnimator設置一個View的透明效果時。它將需要2倍離屏的渲染緩沖填充率,當應用一個alpha到一個大的View上的時候,考慮設置view 層的類型為LAYER_TYPE_HARDWARE。

熱門評論
最新評論
第 1 樓 上海有線通 網(wǎng)友 客人 發(fā)表于: 2012/10/18 14:02:21
謝謝,學習了,蠻好的~~

支持( 0 ) 蓋樓(回復)

發(fā)表評論 查看所有評論(0)
昵稱:
表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
字數(shù): 0/500 (您的評論需要經(jīng)過審核才能顯示)