Android 4.0硬體加速的使用

iteye_21202發表於2013-04-28

1.Android4.0硬體加速的使用

1.1硬體加速的控制級別

啟用硬體加速的最簡單方法就是為整個系統開啟硬體加速的全域性設定。如果你的程式是標準View或者是Drawable則硬體加速的全域性設這並不會造成不良的影響。然而硬體加速並不支援所有2D畫的操作,所以開啟硬體加速可能會對使用自定義元件的應用程式造成影響,問題常常表現在不可見的元素異常和錯誤的畫素渲染,為了解決這個問題Android可以讓你選擇啟動或者禁用以下級別的硬體加速:ApplicationActivityWindow和View。

1.1.1Application級別

在你的AndroidManifest檔案中新增屬性標記,以便為整個應用程式使用硬體加速。

1.1.2Activity級別

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

1.1.3Window級別

如果你需要更細粒度的控制,你可以通過如下程式碼給window進行加速。

  1. getWindow().setFlags(
  2. WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);

注意:現階段你不能在Window級別對它禁用硬體加速。

1.1.4View級別

我們可以對單獨的View在執行時階段禁用硬體加速。我們可以使用如下程式碼:

  1. myView.setLayerType(View.LAYER_TYPE_SOFTWARE,null);

注意:現階段不能夠在View級別進行硬體加速。

1.2判斷一個View是否已經啟用了硬體加速

有時候我們需要知道一個應用程式是否已經啟用了硬體加速,特別是針對一些自定義控制元件。因為你的應用程式做了很多自定義“畫”的操作,但並不是所有的過程都支援新的“畫”的渲染過程。

有兩種不同的方法來檢查Application是否啟用了硬體加速:

1.2.1使用View.isHardwareAccelerated()如果返回true則可以說明這個View所在的視窗已經啟用了硬體加速。

1.2.2Canvas.isHardwareAccelerated()如果返回true則說明這個Canvas已經啟用了硬體加速。

如果你必須要在你的繪畫程式碼中進行是否已經加速的檢查,如果可能的話請使用Canvas.isHardwareAccelerated()來代替View.isHardwareAccelerated()。當一個View是存在於一個已經加速的Windows上時,任然可以使用沒有硬體加速的Canvas進行繪畫,這場發生在,比如,當我們把一個View畫到Bitmap上然後用作快取。

2.Android4.0的繪製模型

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

2.1基於軟體的繪製模型

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

當一個應用程式需要更新它UI的一部分時,它將會呼叫內容發生改變的View的invalidate()方法(或者invalidate的變體)。Invalidate的訊息按照View的層級關係向上傳遞用以計算需要重畫的部分(即髒區域)。然後Android系統會對和髒區域有交集的所有View進行繪製,不幸的是這種模型中有兩個缺點:

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

2.1.2第二個問題是這種繪製模型會隱藏你Application中的Bug。因為Android系統會對和髒區域有交集的View進行重繪,在這種情況下如果一個view的內容發生了改變,即便這個View的Invalidate()的方法並沒有得到呼叫,它也可能被重繪。你便會依賴呼叫了invalidate()的其他的控制元件以便獲得正確的行為,因此每當你的Application發生改變時,這種行為多要隨之發生改變。也是基於次因,在你的自定義控制元件中你必須不斷地呼叫invalidate()方法,當你的資料或者是狀態會影響View的繪製程式碼時。

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

2.2基於硬體加速模型

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

使用這個模型你不能依賴一個View和髒區域有交集就會執行draw()方法。要確保Android系統記錄了一個View的顯示列表,你必須呼叫invalidate()方法,如果忘記了呼叫重新整理,會使View即便是發生了改變後也會看起來相同,這是一個比較容易發現bug的方式。

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

◆DrawDisplayList(ListView);

◆DrawDisplayList(Button);

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

◆SaveLayerAlpha(0.5)

◆DrawDisplayList(ListView)

◆Restore

◆DrawDisplayList(Button)

這時候繪製Listview的複雜過程就會省略了,取而代之的是簡單的更新了LinearLayout的顯示列表。如果一個應用程式並沒有啟用硬體加速,Listview和它的父view的畫的程式碼都會重新執行。

3.Android4.0View的層

3.1層的分類

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

由Android3.0開始你就能夠通過View.setLayerType()方法對何時以及如何使用層有了更多的控制,這個API具有兩個引數一個是你想使用的層型別,另外一個是可選引數Paint表明了Layer是如何被疊加的。你可以把Paint引數應用到顏色過濾上,特別是混合模式或者是對一個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被渲染為一個層,它的繪製程式碼將不會得到執行,直到你呼叫了invalidate()函式。對於一些動畫,比如透明動畫可以直接應用到一個層上,這是GPU最有效率的使用方式。

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

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

3.3View的層和動畫的關係

當你的應用程式已經使用了硬體加速的話,硬體層能夠帶來更為快速和更為平滑的動畫效果。當對一個複雜的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旋轉。

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

因為硬體層會消耗視訊的記憶體,強烈的推薦你在作動畫的時候啟用他們,當動畫完成了之後禁用他們,你可以通過動畫監聽來完成這些。程式碼如下:

  1. View.setLayerType(View.LAYER_TYPE_HARDWARE,null);
  2. ObjectAnimatoranimator=ObjectAnimator.ofFloat(view,"rotationY",180);
  3. animator.addListener(newAnimatorListenerAdapter(){
  4. @Override
  5. publicvoidonAnimationEnd(Animatoranimation){
  6. view.setLayerType(View.LAYER_TYPE_NONE,null);
  7. }
  8. });
  9. animator.start();

4Android4.0提示和技巧

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

4.1減少你程式中使用View的數量

你係統中畫的view的數量越多,你的程式就會越慢,在軟體繪製的流程也是一樣的,減少view的數量是優化你UI的一個最簡單的方法。

4.2避免過多繪製

不要過多的疊加層,當一個View被其他view完全遮擋住了的話,最好把被遮擋的view移除掉。如果你需要繪製不同的層做一個疊加效果的話,考慮把這些層合併為一個層。就現在的硬體來看,有一個好的經驗就是動畫的每幀不要繪製多餘螢幕畫素2.5倍的畫素數量(bimap中的透明畫素也計算在內)。

4.3不要在繪製的方法中建立繪製物件

一個常見的錯誤就是當繪製方法被呼叫的時候,每次都要建立一個新的Paint或者Path。這將迫使垃圾回收器過於頻繁的執行,這將對緩衝和硬體的繪製造成影響。

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

以複雜的shapes,path和旋轉為例,這些繪製都會用到紋理的遮罩。每當你建立或者修改一個path,硬體渲染過程都會建立一個新的遮罩,這耗費的代價是相當大的。

4.5不要過於頻繁的修改bitmap

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

4.6要小心使用alpha通道

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

本文作者的微博為http://weibo.com/zuiniuwang歡迎大家與他聯絡。





相關文章