在一般的Android程序中,UI都是在主線程處理,但是,有些可能比較復雜的動畫會卡頓主線程,如相機,為了解決這個問題,Android提供了SurfaceView,即在非主線程繪制UI。
SurfaceView在android.view包下,從Android1.0開始支持。
public class MySurface extends SurfaceView implements Runnable{}
從中可以看出,我們在使用SurfaceView
時,一般是自定義一個類,并繼承SurfaceView
和Runnable
,熟悉Java的應該能知道,Runnable
是實現多線程的接口,由此可見,我們定義的MySurface
有多線程的特征。
那SurfaceView
又是什么呢?
從官方文檔看,SurfaceView
繼承自android.view.View,也就是說,SurfaceView
也是和ImageView
,TextView
類似的一個普通的View。
然后再看看官方對SurfaceView
的介紹:
第一句提供一個嵌入在View樹,專用于繪制Surface
,View樹我想大家都知道類似如下,可以用Android Tool:View Hierarchy查看
那什么是Surface呢?
從中可以看到,
Surface
繼承自Object
而不是View
,且實現了Parcelable
,可見Surface
不是一個傳統意義上的View
。再看看官方介紹
介紹很簡短的一句話:由屏幕顯示內容合成器(screen compositor)所管理的原始緩沖區的句柄,從中可以看到,
Surface
是個句柄,通過這個句柄,可以獲得原始緩沖區及其內容,原始緩沖區用于保存當前窗口的像素數據。
從Surface
的公開方法中,可以看到有一個lockCanvas
方法,傳入一個矩形區域,返回一個Canvas
。
Canvas
大家應該很熟悉,從字面直譯是畫布的意思,也就是說,你可以在Canvas
這塊畫布上繪制你想要的圖像,實際上也是這個用途
看一下
lockCanvas
的介紹
從Surface
獲取一塊畫布用于繪制,在繪制結束后,調用者必須執行unlockCanvasAndPost(Canvas)
來將新繪制的內容發送到Surface
。
再看看參數inOutDirty
:調用者想要重新繪制的一塊廢棄區域,這個方法可以被用于擴展dirty區域,比如像縮放Surface
,調用者也可以傳遞null
,如果是這樣的話,整個Surface
應該被重新繪制。
而unlockCanvasAndPost(Canvas)
這個方法則是將Canvas
中繪制的內容發送給Surface
。
由此可見,雖然Surface
沒有繼承自View
,但是它擁有一塊可繪制區域用于繪制內容,但是因為它沒有繼承自View
,所以不能直接用于View
樹。
說到這里,應該能明白SurfaceView
是什么了吧,接著看SurfaceView
官方文檔:
You can control the format of this surface and, if you like, its size; the SurfaceView takes care of placing the surface at the correct location on the screen
:“你可以控制Surface
的格式,甚至尺寸,和位置”,從這里可以看出,SurfaceView存在的意義就是將不可以插入View hierarchy的Surface
轉為可以插入的SurfaceView
。
The surface is Z ordered so that it is behind the window holding its SurfaceView; the SurfaceView punches a hole in its window to allow its surface to be displayed. The view hierarchy will take care of correctly compositing with the Surface any siblings of the SurfaceView that would normally appear on top of it. This can be used to place overlays such as buttons on top of the Surface, though note however that it can have an impact on performance since a full alpha-blended composite will be performed each time the Surface changes.
Surface
是在Z軸的,所以它應該在SurfaceView
的底部,SurfaceView
在自己身上打了個洞以便讓Surface
能被看到,View hierarchy會正確的顯示Surface
的位置,其他的View
也可以出現在它的上方,這可以用于將一個按鈕放置在Surface
的上方,需要注意的是,將一個透明的按鈕放置在Surface
的上方,每次Surface
的變化都會導致按鈕的重新繪制。
再看看這句Access to the underlying surface is provided via the SurfaceHolder interface, which can be retrieved by calling getHolder()
“需要訪問底層的Surface
,你可以通過提供的SurfaceHolder
來訪問,SurfaceHolder
可以通過getHolder()
得到”。
The Surface will be created for you while the SurfaceView's window is visible; you should implement surfaceCreated(SurfaceHolder) and surfaceDestoryed(SurfaceHolder) to discover when the Surface is created and destroyed as the window is shown and hidden.
只有SurfaceView
可見是,Surface
才會被創建,你可以繼承surfaceCreated
和surfaceDestoryed
獲得。
到此,SurfaceView
是什么應該能明白了吧。