SurfaceView 与view区别详解

SurfaceView 与view区别详解

 

https://blog.csdn.net/u011339364/article/details/83347109html

 

在Android系统中,有一种特殊的视图,称为SurfaceView,它拥有独立的绘图表面,即它不与其宿主窗口共享同一个绘图表面,因为拥有独立的绘图表面,所以SurfaceView的UI就能够在一个独立的线程中进行行绘制,因为不占用主线程资源,SurfaceView一方面能够实现复杂而高效的UI。android

SurfaceView的绘制方式效率很是高,由于SurfaceView的窗口刷新的时候不须要重绘应用程序的窗口(android普通窗口的视图绘制机制是一层一层的,任何一个子元素或者是局部的刷新都会致使整个视图结构所有重绘一次,所以效率很是低下)。
View经过刷新来重绘视图,Android系统经过发出VSYNC信号来进行屏幕的重绘,刷新的时间间隔通常为16ms,在一些须要频繁刷新的界面,若是刷新执行不少逻辑绘制操做,就会致使刷新使用时间超过了16ms,就会致使丢帧或者卡顿,好比你更新画面的时间过长,那么你的主UI线程会被你的绘制函数阻塞,那么将没法响应按键,触屏等消息,会形成 ANR 问题,SurfaceView虽然继承自View,但拥有独立的surface,即它不与其宿主窗口共享同一个surface,能够单独在一个线程进行绘制,并不会占用主线程的资源,这样,绘制就会比较高效,游戏,视频播放,直播,均可以用SurfaceView来实现,SurfaceView有两个子类GLSurfaceView和VideoView
canvas

 

SurfaceView里面镶嵌的Surface是在包含SurfaceView的宿主Activity窗口(顶层视图对应的Surface)后面,用来描述SurfaceView的Layer的Z轴位置是小于用来描述其宿主Activity窗口的Layer的Z轴位置的,这样SurfaceView的Layer就被挡住看不见了,SurfaceView提供了一个可见区域,只有在这个可见区域内的surface部份内容才可见,就好像SurfaceView会在宿主Activity窗口上面挖一个“洞”出来,以便它的UI能够漏出来对用户可见,实际上,SurfaceView只不过是在其宿主Activity窗口上设置了一块透明区域缓存

如上Activity窗口的顶层视图DecorView及其两个TextView控件都是经过窗口的Surface对应的Canvas绘制在SurfaceFlinger服务中的同一个Layer上,而SurfaceView的UI是经过其本身的Surface对应的Canvas绘制在SurfaceFlinger服务中的另一个Layer上。ide

要了解 SurfaceView ,还须了解它的另外两个组件:Surface 和 SurfaceHolder,他们三者之间的关系实质上就是 MVC,Model就是数据模型的意思也就是这里的Surface;View即视图也就是这里的SurfaceView;SurfaceHolder很明显能够理解为Controller(控制器)。函数

在SurfaceView中你能够经过SurfaceHolder接口访问它内部的surface,而咱们执行绘制的方法就是操做这个 Surface内部的Canvas,处理Canvas画的效果和动画,大小,像素等,getHolder()方法能够获得这个SurfaceHolder,经过SurfaceHolder来控制surface的尺寸和格式,或者修改监视surface的变化等等。动画

SurfaceHolder有三个回调方法能够监听SurfaceView中的surface的生命周期,SurfaceView一开始建立出来后,它拥有的Surface不必定会一块儿建立出来,SurfaceView变得可见时,surface被建立,SurfaceView隐藏前,surface被销毁,被建立了表示能够开始准备绘制了,而被销毁后咱们要释放其余资源,Surfaceview通常会继承SurfaceHolder的Callback接口,SurfaceHolder.Callback具备以下的方法:
   surfaceCreated(SurfaceHolder holder):当Surface第一次建立后会当即调用该函数,能够在该函数中作些和绘制界面相关的初始化工做,通常状况下都是在新线程来绘制界面,因此不要在这个函数中绘制Surface。 
   surfaceChanged(SurfaceHolder holder, int format, int width,int height):当Surface的状态(大小和格式)发生变化的时候会调用该函数,在surfaceCreated调用后该函数至少会被调用一次。 
   surfaceDestroyed(SurfaceHolder holder):当Surface被摧毁前会调用该函数,该函数被调用后就不能继续使用Surface了,通常在该函数中来清理使用的资源。 spa

特别须要注意的是SurfaceView和SurfaceHolder.Callback的全部回调方法都是在主线程中回调的,在绘制前必须先合法的获取 Surface 才能开始绘制内容, SurfaceHolder.Callback.surfaceCreated() 和 SurfaceHolder.Callback.surfaceDestroyed() 之间的状态为合法的,在这以外使用Surface都会出错。.net

在使用SurfaceView过程当中是不直接和Surface打交道的,由SurfaceHolder的Canvas lockCanvas()或则Canvas lockCanvas(Rect dirty)函数来锁定而且获取Surface中的Canvas画布对象,经过在Canvas上绘制内容来修改Surface中的数据,若是Surface被别的线程占有不可编辑或则还没有建立或者已经被销毁,调用该函数会返回null。线程

在unlockCanvas() 和 lockCanvas()之间Surface的内容是不缓存的,因此须要彻底重绘Surface的内容,若是为了提升效率只重绘变化的部分则能够调用lockCanvas(Rect dirty)函数来指定一个dirty区域,这样该区域外的内容会缓存起来,只更新须要重绘的区域,相对部份内存要求比较高的游戏来讲,不重画dirty外的其余区域的像素,能够提升速度。

在调用lockCanvas函数获取Surface的Canvas后,SurfaceView会利用Surface的一个同步锁锁住画布Canvas,直到调用unlockCanvasAndPost(Canvas canvas)函数,才解锁画布并提交改变,将图形显示,这里的同步机制保证Surface的Canvas在绘制过程当中不会被改变(被摧毁、修改),避免多个不一样的线程同时操做同一个Canvas对象。

双缓冲:SurfaceView在更新视图时用了两个Canvas,一张frontCanvas和一张backCanvas,每次实际显示的是frontCanvas,backCanvas存储的是上一次更改前的视图,当使用lockCanvas()获取画布时,获得的其实是backCanvas而不是正在显示的frontCanvas,当你在获取到的backCanvas上绘制完成后,再使用unlockCanvasAndPost(canvas)提交backCanvas视图,那么这张backCanvas将替换正在显示的frontCanvas被显示出来,原来的frontCanvas将切换到后台做为backCanvas,这样作的好处是在绘制期间不会出现黑屏。

SurfaceView类的成员变量mRequestedType描述的是SurfaceView的绘图表面Surface的类型,通常来讲,它的值可能等于SURFACE_TYPE_NORMAL或者SURFACE_TYPE_PUSH_BUFFERS,
当一个SurfaceView的绘图表面的类型等于SURFACE_TYPE_NORMAL的时候,就表示该SurfaceView的绘图表面所使用的内存是一块普通的内存,通常来讲,这块内存是由SurfaceFlinger服务来分配的,咱们能够在应用程序内部自由地访问它,便可以在它上面填充任意的UI数据,而后交给SurfaceFlinger服务来合成,而且显示在屏幕上,在这种状况下,在SurfaceFlinger服务一端使用一个Layer对象来描述该SurfaceView的绘图表面。

当一个SurfaceView的绘图表面的类型等于SURFACE_TYPE_PUSH_BUFFERS的时候,就表示该SurfaceView的绘图表面所使用的内存不是由SurfaceFlinger服务分配的,咱们不可以在应用程序内部对它进行操做,因此不能调用lockCanvas来获取Canvas对象进行绘制了,例如当一个SurfaceView是用来显示摄像头预览或者视频播放的时候,咱们就会将它的绘图表面的类型设置为SURFACE_TYPE_PUSH_BUFFERS,这样摄像头服务或者视频播放服务就会为该SurfaceView绘图表面建立一块内存,而且将采集的预览图像数据或者视频帧数据源源不断地填充到该内存中去,在这种状况下,在SurfaceFlinger服务一端使用一个LayerBuffer对象来描述该SurfaceView的绘图表面。因此:决定surfaceView的内存是普通内存(由开发者本身决定用来绘制什么)仍是专用的内存(显示摄像头或者视频等,开发者没法使用这块内存)由mRequestType决定,咱们在建立了一个SurfaceView以后,能够调用它的SurfaceHolder对象的成员函数setType来修改该SurfaceView的绘图表面的类型,绘图表面类型为SURFACE_TYPE_PUSH_BUFFERS的SurfaceView的UI是不能由应用程序来控制的,而是由专门的服务来控制的,例如,摄像头服务或者视频播放服务。SurfaceView类的成员变量mRequestedType目前接收以下的参数:SURFACE_TYPE_NORMAL:用RAM缓存原生数据的普通Surface SURFACE_TYPE_HARDWARE:适用于DMA(Direct memory access )引擎和硬件加速的Surface SURFACE_TYPE_GPU:适用于GPU加速的Surface SURFACE_TYPE_PUSH_BUFFERS:代表该Surface不包含原生数据,Surface用到的数据由其余对象提供。