Android SurfaceView與TextureView使用方法詳細講解
Surface
官方對Surface的解釋是:由屏幕合成器管理的原始緩沖區上的句柄,所謂原生緩沖器,是用於保存當前窗口的像素數據的,也就是說,通過Surface可以獲取原生緩沖器以及其中的內容。Surface對應一塊屏幕緩沖區,每個Window對應一個Surface,任何View都畫在Surface上,Surface中的Canvas,是用於提供畫圖的地方。
SurfaceView
SurfaceView與普通的View不同,它擁有自己的Surface,它的工作方式是創建一個區別於應用窗口的新窗口,與宿主窗口分離,可以在單獨線程中處理業務,不受View的屬性控制,無法進行平移縮放等轉換,它是通過“雙緩沖”機制來達到高效的界面刷新效果。
雙緩沖技術是把要處理的圖片在內存中處理好之後,再將其顯示在屏幕上。雙緩沖主要是為瞭解決反復局部刷屏帶來的閃爍。把要畫的東西先畫到一個內存區域裡,然後整體的一次性畫出來。
下面通過一個相機預覽的功能,來看一下SurfaceView的具體使用
private lateinit var surfaceHolder: SurfaceHolder
獲取攝像機管理類,打開某個具體的攝像機,在打開成功的回調裡面,創建預覽請求
val cameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManager val surfaceView = findViewById<SurfaceView>(R.id.surfaceView) surfaceHolder = surfaceView.holder surfaceHolder.setKeepScreenOn(true) surfaceHolder.addCallback(object : SurfaceHolder.Callback { override fun surfaceCreated(p0: SurfaceHolder) { if (ActivityCompat.checkSelfPermission( this@SurfaceActivity, Manifest.permission.CAMERA ) != PackageManager.PERMISSION_GRANTED ) { //無相機權限 return } try { //獲取可用相機設備列表 val cameraIdList = cameraManager.cameraIdList //打開相機 cameraManager.openCamera( cameraIdList[0], //攝像頭創建監聽 object : CameraDevice.StateCallback() { override fun onOpened(p0: CameraDevice) { //打開攝像頭 try { startPreview(p0) } catch (e: CameraAccessException) { e.printStackTrace() } } override fun onDisconnected(p0: CameraDevice) { //關閉攝像頭 p0.close() } override fun onError(p0: CameraDevice, p1: Int) { Log.i(tag, "CameraDevice.StateCallback onError") } }, null ) } catch (e: CameraAccessException) { e.printStackTrace() } } override fun surfaceChanged(p0: SurfaceHolder, p1: Int, p2: Int, p3: Int) { Log.i(tag, "surfaceChanged") } override fun surfaceDestroyed(p0: SurfaceHolder) { Log.i(tag, "surfaceDestroyed") } })
開始預覽
private fun startPreview(cameraDevice: CameraDevice) { val captureRequest = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) captureRequest.addTarget(surfaceHolder.surface) cameraDevice.createCaptureSession( listOf(surfaceHolder.surface), //會話狀態回調 object : CameraCaptureSession.StateCallback() { override fun onConfigured(p0: CameraCaptureSession) { try { // 創建預覽需要的CaptureRequest.Builder val previewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) previewRequestBuilder.addTarget(surfaceHolder.surface) val previewRequest = previewRequestBuilder.build() p0.setRepeatingRequest(previewRequest, null, null) } catch (e: CameraAccessException) { e.printStackTrace() } } override fun onConfigureFailed(p0: CameraCaptureSession) { Log.i(tag, "onConfigureFailed") } }, null ) }
這樣,簡易的相機預覽功能就出來啦,當然,我們還需要申請CAMERA權限,這裡略去。
TextureView
TextureView可以說是一個結合瞭View和SurfaceTexture的View對象,一個可以把內容流作為外部紋理輸出在上面的 View,它隻能用於開啟瞭硬件加速的窗口,TextureView不會創建一個獨立的窗口,而是像普通的View一樣,可以進行平移、旋轉等動畫,TextureView在Andriod 4.0之後的 API 中才能使用,不過現在的安卓設備基本不存在Andriod 4.0之前的版本瞭,所以這點不必在意。
TextureView的使用也比較簡單,需要獲取到它的SurfaceTexture,然後就可以以此來渲染瞭,下面通過一個簡易的視頻播放的示例,來瞧瞧它是怎麼使用的。
val textureView = findViewById<TextureView>(R.id.textureView) val mediaPlayer = MediaPlayer() textureView.surfaceTextureListener = object : TextureView.SurfaceTextureListener { override fun onSurfaceTextureAvailable(p0: SurfaceTexture, p1: Int, p2: Int) { with(mediaPlayer) { setDataSource(GlobalData.videoUrl) setSurface(Surface(p0)) prepare() start() Log.i(tag, "setOnPreparedListener") setOnPreparedListener { it.start() } } } override fun onSurfaceTextureSizeChanged(p0: SurfaceTexture, p1: Int, p2: Int) { } override fun onSurfaceTextureDestroyed(p0: SurfaceTexture): Boolean { mediaPlayer.stop() mediaPlayer.release() return true } override fun onSurfaceTextureUpdated(p0: SurfaceTexture) { } }
SurfaceTexture
SurfaceTexture是Surface和OpenGL ES紋理的組合,用於提供輸出到OpenGL ES紋理的Surface,和SurfaceView不同的是,它對圖像流的處理並不直接顯示,而是轉為GL外部紋理,因此可用於圖像流數據的二次處理,如Camera濾鏡,桌面特效等,但是這樣會有若幹幀的延遲。同時,由於它本身管理BufferQueue,因此內存消耗也會稍微大一些。比如Camera的預覽數據,變成紋理後就可以通過SurfaceTexture交給TextureView作為View層級中的一個硬件加速層來顯示。
SurfaceView和TextureView的區別
- SurfaceView是直接輸出的,擁有自己獨立Surface,它的渲染可以放在單獨線程,其缺點是不能做變形和動畫。
- TextureView是一個可以把內容流作為外部紋理輸出的,本身必須是一個硬件加速層,顯示畫面更新時有1~3幀的延遲。
- TextureView本身也包含瞭SurfaceTexture,它與SurfaceView+SurfaceTexture組合相比,也可以把內容流上的圖像轉成紋理輸出,區別在於TextureView是在View層級中繪制的,而SurfaceView+SurfaceTexture在單獨的Surface上做繪制的。
SurfaceView | TextureView |
---|---|
占用內存低 | 占用內存高 |
耗電低 | 耗電高 |
繪制及時 | 1-3幀延時 |
不支持動畫截圖 | 支持動畫截圖 |
個人覺得,對於需要不斷更新畫佈的遊戲來說,SurfaceView是最好的選擇,對於視頻播放器或相機應用的開發,則TextureView更加適合。
到此這篇關於Android SurfaceView與TextureView使用方法詳細講解的文章就介紹到這瞭,更多相關Android SurfaceView與TextureView內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Android SurfaceView基礎用法詳解
- Android中SurfaceView和普通view的區別及使用
- Android中常見的圖形繪制方式總結
- Android自定義相機聚焦和顯示框
- Android Camera開發實現可復用的相機組件