一、SurfaceView的概念
第一次接触SurfaceView,找了很多资料才理解SurfaceView概念,总结查资料的结果。Android中有一种特殊的视图,称为SurefaceView,与平时时候的 TextView、Button的区别:
- 它拥有独立的特殊的绘制表面,即 它不与其宿主窗口共享一个绘制表面
- SurefaceView的UI可以在一个独立的线程中进行绘制
- 因为不会占用主线程资源,一方面可以实现复杂而高效的UI,二是不会导致用户输入得不到及时响应
二、为什么需要SurfaceView
普通空间,TextView,Button等,都是讲自己的UI绘制在宿主窗口的绘制表面Surface之上,意味着他们的UI在应用程序的主线程中绘制的。但是主线程除了绘制UI之外,还要及时响应用户输入,手势等,否则,系统会认为应用程序没响应,ANR。
因此,对一些游戏画面,或者摄像头,视频播放等,UI都比较复杂,要求能够进行高效的绘制,因此,他们的UI不适合在主线程中绘制。这时候就必须要给那些需要复杂而高效的UI视图生成一个独立的绘制表面Surface,并且使用独立的线程来绘制这些视图UI。
三、理解SurfaceView的形成
每个窗口在SurfaceFlinger服务中都对应有一个layer,用来描述它的绘制表面surface。对于那些具有SurfaceView的窗口来说,每个SurfaceFlinger服务中还对应一个独立的Layer或者LayerBuffer,用来单独描述它的绘制表面,以区别它的宿主窗口的绘制表面。
在图1中,Activity窗口的顶层视图DecorView及其两个TextView控件的UI都是绘制在SurfaceFlinger服务中的同一个Layer上面的,而SurfaceView的UI是绘制在SurfaceFlinger服务中的另外一个Layer或者LayerBuffer上的。
注意,用来描述SurfaceView的Layer或者LayerBuffer的Z轴位置是小于用来其宿主Activity窗口的Layer的Z轴位置的,但是前者会在后者的上面挖一个“洞”出来,以便它的UI可以对用户可见。实际上,SurfaceView在其宿主Activity窗口上所挖的“洞”只不过是在其宿主Activity窗口上设置了一块透明区域。
四、SurfaceView的绘制过程
SurfaceView虽然具有独立的绘图表面,不过它仍然是宿主窗口的视图结构中的一个结点,因此,它仍然是可以参与到宿主窗口的绘制流程中去的。从Android应用程序窗口(Activity)的测量(Measure)、布局(Layout)和绘制(Draw)过程分析可以知道,窗口在绘制的过程中,每一个子视图的成员函数draw或者dispatchDraw都会被调用到,以便它们可以绘制自己的UI。 SurfaceView类的成员函数draw和dispatchDraw的实现如下所示:
SurfaceView类的成员函数draw和dispatchDraw的参数canvas所描述的都是建立在宿主窗口的绘图表面上的画布,因此,在这块画布上绘制的任何UI都是出现在宿主窗口的绘图表面上的.
本来SurfaceView类的成员函数draw是用来将自己的UI绘制在宿主窗口的绘图表面上的,但是这里我们可以看到,如果当前正在处理的SurfaceView不是用作宿主窗口面板的时候,即其成员变量mWindowType的值不等于WindowManager.LayoutParams.TYPE_APPLICATION_PANEL的时候,SurfaceView类的成员函数draw只是简单地将它所占据的区域绘制为黑色。
本来SurfaceView类的成员函数dispatchDraw是用来绘制SurfaceView的子视图的,但是这里我们同样看到,如果当前正在处理的SurfaceView不是用作宿主窗口面板的时候 ,那么SurfaceView类的成员函数dispatchDraw只是简单地将它所占据的区域绘制为黑色,同时,它还会通过调用另外一个成员函数updateWindow更新自己的UI,实际上就是请求WindowManagerService服务对自己的UI进行布局,以及创建绘图表面
从SurfaceView类的成员函数draw和dispatchDraw的实现就可以看出,SurfaceView在其宿主窗口的绘图表面上面所做的操作就是将自己所占据的区域绘为黑色,除此之外,就没有其它更多的操作了,这是因为SurfaceView的UI是要展现在它自己的绘图表面上面的。接下来我们就分析如何在SurfaceView的绘图表面上面进行UI绘制。
如果要在一个绘图表面进行UI绘制,那么就顺序执行以下的操作:
- 在绘图表面的基础上建立一块画布,即获得一个Canvas对象。
- 利用Canvas类提供的绘图接口在前面获得的画布上绘制任意的UI。
- 将已经填充好了UI数据的画布缓冲区提交给SurfaceFlinger服务,以便SurfaceFlinger服务可以将它合成到屏幕上去。
五、Surface,SurfaceView,SurfaceHolder分析
- Surface:
处理被屏幕排序的原生的buffer,Android中的Surface就是一个用来画图形(graphics)或图像(image)的地方,对于View及其子类,都是画在Surface上,各Surface对象通过Surfaceflinger合成到frameBuffer,每个Surface都是双缓冲(实际上就是两个线程,一个渲染线程,一个UI更新线程),它有一个backBuffer和一个frontBuffer,Surface中创建了Canvas对象,用来管理Surface绘图操作,Canvas对应Bitmap,存储Surface中的内容。
- SurfaceView:
SurfaceView是View的子类,且实现了Parcelable接口且实现了Parcelable接口,其中内嵌了一个专门用于绘制的Surface,SurfaceView可以控制这个Surface的格式和尺寸,以及Surface的绘制位置。可以理解为Surface就是管理数据的地方,SurfaceView就是展示数据的地方。
- SurfaceHolder:
一个管理SurfaceHolder的容器。SurfaceHolder是一个接口,可理解为一个Surface的监听器。 通过回调方法addCallback(SurfaceHolder.Callback callback )监听Surface的创建 通过获取Surface中的Canvas对象,并锁定之。所得到的Canvas对象 通过当修改Surface中的数据完成后,释放同步锁,并提交改变Surface的状态及图像,将新的图像数据进行展示。-
而最后综合:SurfaceView中调用getHolder方法,可以获得当前SurfaceView中的Surface对应的SurfaceHolder,SurfaceHolder开始对Surface进行管理操作。这里其实按MVC模式理解的话,可以更好理解。M:Surface(图像数据),V:SurfaceView(图像展示),C:SurfaceHolder(图像数据管理)。
转载:https://blog.csdn.net/weixin_42600398/article/details/116605926