SurfaceView 和 TextureView

简介: SurfaceView 和 TextureView

在说这两个之前,我们先说一下什么是surface

在SDK的文档中,对Surface的描述是这样的:“Handle onto a raw  buffer that is being managed by the screen 
compositor”,翻译成中文就是“由屏幕显示内容合成器(screen compositor)所管理的原始缓冲区的句柄”
简单来说就是,Surface对应了一块屏幕缓冲区,每个window对应一个Surface,任何View都要画在Surface的Canvas上
(后面有原因解释)。传统的view共享一块屏幕缓冲区,所有的绘制必须在UI线程中进行。
surface中的canvas就是专门用来画图的,缓冲区是用来保存数据的,而surface就是一个句柄,得到surface就可以得到
画图的canvas和保存数据的缓冲区

说完surface就可以说SurfaceView 了 SurfaceView就是指一个在表层的View对象。为什么说是表层呢,因为你说它是一个纯粹view也许不够严谨,它有自己的Surface。有自己的Surface,在WMS中有对应的WindowState,在SurfaceFlinger中有Layer。我们知道,一般的Activity包含的多个View会组成View hierachy的树形结构,只有最顶层的DecorView,也就是根结点视图,才是对WMS可见的。这个DecorView在WMS中有一个对应的WindowState。相应地,在SF中对应的Layer。而SurfaceView自带一个Surface,这个Surface在WMS中有自己对应的WindowState,在SF中也会有自己的Layer。虽然在App端它仍在View hierachy中,但在Server端(WMS和SF)中,它与宿主窗口是分离的。这样的好处是对这个Surface的渲染可以放到单独线程去做,渲染时可以有自己的GL context。这对于一些游戏、视频等性能相关的应用非常有益,因为它不会影响主线程对事件的响应。但它也有缺点,因为这个Surface不在View hierachy中,它的显示也不受View的属性控制,所以不能进行平移,缩放等变换,也不能放在其它ViewGroup中,一些View中的特性也无法使用。而且,SurfaceView默认使用双缓冲技术的,它支持在子线程中绘制图像,这样就不会阻塞主线程

解释下双缓冲:

可以理解为:SurfaceView在更新视图时用到了两张Canvas,一张frontCanvas和一张backCanvas,每次实际显示的是
frontCanvas,backCanvas存储的是上一次更改前的视图,当使用lockCanvas()获取画布时,得到的实际上是backCanvas
而不是正在显示的frontCanvas,之后你在获取到的backCanvas上绘制新视图,再unlockCanvasAndPost(canvas)此视图,
那么上传的这张canvas将替换原来的frontCanvas作为新的frontCanvas,原来的frontCanvas将切换到后台作为backCanvas。
例如,如果你已经先后两次绘制了视图A和B,那么你再调用lockCanvas()获取视图,获得的将是A而不是正在显示的B,之后
你讲重绘的C视图上传,那么C将取代B作为新的frontCanvas显示在SurfaceView上,原来的B则转换为backCanvas。

那么SurfaceView的优缺点就很明确了:

优点:
可以在一个独立的线程中进行绘制,不会影响主线程
使用双缓冲机制,播放视频时画面更流畅
缺点:
虽然继承自view,但是view的很多属性是用不了的,Surface不在View hierachy中,它的显示也不受View的属性控制,所以不能进行平移,缩放等变换,也不能放在其它ViewGroup中。SurfaceView 不能嵌套使用

SurfaceView就说这么多,下面我们来说说TextureView

TextureView 在4.0(API level 14)中引入,与SurfaceView一样继承View,专门用来渲染像视频或OpenGL场景之类的数据的,而且TextureView只能用在具有硬件加速的Window中,如果使用的是软件渲染,TextureView将什么也不显示。也就是说对于没有GPU的设备,TextureView完全不可用

TextureView 可以将内容流直接投影到View中,它可以将内容流直接投影到View中,可以用于实现Live preview等功能。和SurfaceView不同,它不会在WMS中单独创建窗口,而是作为View hierachy中的一个普通View,因此可以和其它普通View一样进行移动,旋转,缩放,动画等变化。值得注意的是TextureView必须在硬件加速的窗口中。它显示的内容流数据可以来自App进程或是远端进程。从类图中可以看到,TextureView继承自View,它与其它的View一样在View hierachy中管理与绘制。TextureView重载了draw()方法,其中主要SurfaceTexture中收到的图像数据作为纹理更新到对应的HardwareLayer中。SurfaceTexture.OnFrameAvailableListener用于通知TextureView内容流有新图像到来。SurfaceTextureListener接口用于让TextureView的使用者知道SurfaceTexture已准备好,这样就可以把SurfaceTexture交给相应的内容源。Surface为BufferQueue的Producer接口实现类,使生产者可以通过它的软件或硬件渲染接口为SurfaceTexture内部的BufferQueue提供graphic buffer。

总结一下TextureView的优缺点:

优点:
就是SurfaceView中不具备的,TextureView是一个真正的view,它具备view的一切属性,可以移动,
旋转,缩放等,而且支持截图
缺点:
必须在硬件加速的窗口中使用,占用内存比SurfaceView高,在5.0以前在主线程渲染,5.0以后有单独的渲染线程。

我们来比较一下两者的性能

指标 SurfaceView TextureView
内存
绘制 及时 1-3帧的延迟
耗电
动画和截图 不支持 支持

对于播放器选择方面,个人建议还是使用SurfaceView,原因如下

1、在android 7.0上系统surfaceview的性能比TextureView更有优势,支持对象的内容位置和包含的应用内容同步更新,
平移、缩放不会产生黑边。 在7.0以下系统如果使用场景有动画效果,可以选择性使用TextureView
2、由于失效(invalidation)和缓冲的特性,TextureView增加了额外1~3帧的延迟显示画面更新
3、TextureView总是使用GL合成,而SurfaceView可以使用硬件overlay后端,可以占用更少的内存带宽,消耗更少的能量
4、TextureView的内部缓冲队列导致比SurfaceView使用更多的内存
5、SurfaceView: 内部自己持有surface,surface 创建、销毁、大小改变时系统来处理的,通过surfaceHolder 的
callback回调通知。当画布创建好时,可以将surface绑定到MediaPlayer中。SurfaceView如果为用户可见的时候,
创建SurfaceView的SurfaceHolder用于显示视频流解析的帧图片,如果发现SurfaceView变为用户不可见的时候,
则立即销毁SurfaceView的SurfaceHolder,以达到节约系统资源的目的


相关文章
|
Android开发
Android 使用MediaPlayer和SurfaceView播放视频
Android 使用MediaPlayer和SurfaceView播放视频
168 0
|
前端开发 Android开发
SurfaceView的那点事儿
SurfaceView的那点事儿
156 0
Android-MediaPlayer(3)加打碟旋转效果
Android-MediaPlayer(3)加打碟旋转效果
212 0
Android-MediaPlayer(3)加打碟旋转效果
|
XML Android开发 数据格式
Fragment生命周期的坑和DialogFragment宽高的坑
最近在开发单页面应用,多个fragment嵌套在一个activity里面,和之前单个Fragment依赖在activivty中管理还是有点不同,我这Fragment嵌套了3层,最终还是出问题了。
2464 0
|
API Android开发 容器
Android Camera2拍照(一)——使用SurfaceView
原文:Android Camera2拍照(一)——使用SurfaceView Camera2 API简介 Android 从5.
3640 0
|
Java Android开发
android mediaplayer SurfaceView
          package com.curiousby.baoyou.cn.DemoMediaPlayer.activity; import android.app.
1044 0