一、SurfaceView
SurfaceView繼承自View,並提供了一個獨立的繪圖層,你可以完全控制這個繪圖層,比如說設定它的大小,所以SurfaceView可以嵌入到View結構樹中,需要注意的是,由於SurfaceView直接將繪圖表層繪制到屏幕上,所以和普通的View不同的地方就在與它不能執行Transition,Rotation,Scale等轉換,也不能進行Alpha透明度運算。
SurfaceView的Surface排在Window的Surface(也就是View樹所在的繪圖層)的下面,SurfaceView嵌入到Window的View結構樹中就好像在Window的Surface上強行打了個洞讓自己顯示到屏幕上,而且SurfaceView另起一個線程對自己的Surface進行刷新。需要注意的是SurfaceHolder.Callback的所有回調方法都是在主線程中回調的。
SurfaceView、SurfaceHolder、Surface的關系可以概括為以下幾點:
- SurfaceView是擁有獨立繪圖層的特殊View。
- Surface就是指SurfaceView所擁有的那個繪圖層,其實它就是內存中的一段繪圖緩沖區。
- SurfaceView中具有兩個Surface,也就是我們所說的雙緩沖機制
- SurfaceHolder顧名思義就是Surface的持有者,SurfaceView就是通過過SurfaceHolder來對Surface進行管理控制的。並且SurfaceView.getHolder方法可以獲取SurfaceView相應的SurfaceHolder。
- Surface是在SurfaceView所在的Window可見的時候創建的。我們可以使用SurfaceHolder.addCallback方法來監聽Surface的創建與銷毀的事件。
Surface的渲染可以放到單獨線程去做,渲染時可以有自己的GL context。這對於一些游戲、視頻等性能相關的應用非常有益,因為它不會影響主線程對事件的響應。但它也有缺點,因為這個Surface不在View hierachy中,它的顯示也不受View的屬性控制,所以不能進行平移,縮放等變換,也不能放在其它ViewGroup中,一些View中的特性也無法使用。
二、TextureView
TextureView專門用來渲染像視頻或OpenGL場景之類的數據的,而且TextureView只能用在具有硬件加速的Window中,如果使用的是軟件渲染,TextureView將什么也不顯示。也就是說對於沒有GPU的設備,TextureView完全不可用。
TextureView 有兩個相關類 SurfaceTexture、Surface,下面說明一下幾者相關的特點:
- Surface就是SurfaceView中使用的Surface,就是內存中的一段繪圖緩沖區。
- SurfaceTexture用來捕獲視頻流中的圖像幀的,視頻流可以是相機預覽或者視頻解碼數據。SurfaceTexture可以作為android.hardware.camera2, MediaCodec, MediaPlayer, 和 Allocation這些類的目標視頻數據輸出對象。可以調用updateTexImage()方法從視頻流數據中更新當前幀,這就使得視頻流中的某些幀可以跳過。
- TextureView可以通過getSurfaceTexture()方法來獲取TextureView相應的SurfaceTexture。但是最好的方式還是使用TextureView.SurfaceTextureListener監聽器來對SurfaceTexture的創建銷和毀進行監聽,因為getSurfaceTexture可能獲取的是空對象。
三、GLSurfaceView
GLSurfaceView作為SurfaceView的補充,可以看作是SurfaceView的一種典型使用模式。在SurfaceView的基礎上,它加入了EGL的管理,並自帶了渲染線程。另外它定義了用戶需要實現的Render接口,提供了用Strategy pattern更改具體Render行為的靈活性。作為GLSurfaceView的Client,只需要將實現了渲染函數的Renderer的實現類設置給GLSurfaceView即可。
四、SurfaceTexture
SurfaceTexture和SurfaceView不同的是,它對圖像流的處理並不直接顯示,而是轉為GL外部紋理,因此可用於圖像流數據的二次處理(如Camera濾鏡,桌面特效等)。比如Camera的預覽數據,變成紋理后可以交給GLSurfaceView直接顯示,也可以通過SurfaceTexture交給TextureView作為View heirachy中的一個硬件加速層來顯示。首先,SurfaceTexture從圖像流(來自Camera預覽,視頻解碼,GL繪制場景等)中獲得幀數據,當調用updateTexImage()時,根據內容流中最近的圖像更新SurfaceTexture對應的GL紋理對象,接下來,就可以像操作普通GL紋理一樣操作它了。