WebView簡介(加速加載篇)


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,放心大膽的開啟硬件加速吧!具體是哪些繪圖操作不支持硬件加速呢?以下是已知不支持硬件加速的繪圖操作:

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. 繪制顯示列表

 

LAYER_TYPE_SOFTWARE
無論硬件加速是否打開,都會有一張Bitmap(software layer),並在上面對WebView進行軟渲染。
好處:
在進行動畫,使用software可以只畫一次View樹,很省。
什么時候不要用:
View樹經常更新時不要用。尤其是在硬件加速打開時,每次更新消耗的時間更多。因為渲染完這張Bitmap后還需要再把這張Bitmap渲染到hardware layer上面去。


LAYER_TYPE_HARDWARE
硬件加速關閉時,作用同software。
硬件加速打開時會在FBO(Framebuffer Object)上面做渲染,在進行動畫時,View樹也只需要畫一次。


兩者區別
1、一個是渲染到Bitmap,一個是渲染到FB上。
2、hardware可能會有一些操作不支持。
兩者相同:
都是開了一個buffer,把View畫到這個buffer上面去。


LAYER_TYPE_NONE
這個就比較簡單了,不為這個View樹建立單獨的layer


PS:GLSurfaceView和WebView默認Layertype都是none。


GLSurfaceView:
給GLSurfaceView設置為software或者hardware后,發現什么也畫不出來了。得出結論:GLSurfaceView的Layer type只能是none


WebView:
以前使用WebView時碰到過一個問題,如果在WebView上面使用Animation,WebView的繪畫區域不動。當時的解決方案是在進行動畫之前對WebView進行截屏(drawingcache)。按上面的道理試了一下,設置一個hardware或者software的layer就OK了。

現在又碰到了另外一個問題,打開硬件加速后,在一些機器上面(我的是3.2)WebView有時會出現某一塊區域白屏的問題。默認的layer type是none,改為hardware也不行,設置為software就解決了。當然關閉硬件加速也好了,可是那樣的話程序整體就比較慢了。所以最終方案是整體硬件加速,出問題的WebView設置software

 

補充於2012.4.21:

加上這一句,可以讓3D的繪制更快一些:getHolder().setType(SurfaceHolder.SURFACE_TYPE_HARDWARE);

 

補充於2012.4.22

先說問題:
在硬件加速開啟的情況下GLSurfaceView一旦被從View樹上摘下來,會使整個窗口背景變黑,即使設置layer type為software也不管用。
經過兩天的排查,發現了原因,我的程序是在C層由drawFrame(屬於GLThread線程)來驅動進行繪畫,當GLSurfaceView被摘下來時,GLSurfaceView的destroy方法被調用,我在destroy方法(屬於UI線程)中直接調用 了GLThread線程的結束方法。而GLSurfaceView.creat,sizeChanged,destroyed在UI線程,Render.create,sizeChanged,drawFrame在GLThread線程。因此,出現了UI線程直接調用GLThread線程的方法的問題。最終通過GLSurfaceView.queueEvent向GLThread線程發送Runnable,問題得到解決。
看來,還是軟渲染的容錯能力比較強,一開硬件加速,底層就比較脆弱了。
結論:一定要搞清楚哪個是UI線程,哪個是GLThread線程。

補上幾個尋找問題過程中發現的知識點:
hardware acclerator是對整個窗口進行加速,在硬件加速打開時View.isHardwareAcclerator返回true。但每個View可能被渲染到的Canvas是不同的,比如View可能被通過setLayer設置了Layer,這時,Canvas.isHardwareAccelerator返回false
Android提供了三種硬件加速是否打開的控制級別,分別是Application,Activity,Window,View。這個可以參考Dev Guide

 

 

 

 

 

 

當我們在使用WebView時,如果加載的網友比較大,這加載速度將非常慢。

現總結幾種加速WebView加載的方法
1、提高渲染的優先級
webView.getSettings().setRenderPriority(RenderPriority.HIGH);
2、使用webView.getSettings().setBlockNetworkImage,把圖片加載放在最后來加載渲染。參照示例1.
3,使用硬件加速,該功能在Android 3.0 (API level 11)才加入。具體參照: http://developer.android.com/guide/topics/graphics/hardware-accel.html
示例1:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM