Android SurfaceView(二、实现原理)

来源:互联网 发布:遗传算法的实现过程 编辑:程序博客网 时间:2024/05/06 20:25

转载自:http://blog.csdn.net/luoshengyang/article/details/8661317


在Android系统中,有一种特殊的视图,称为SurfaceView,它拥有独立的绘图表面,即它不与其宿主窗口共享同一个绘图表面。由于拥有独立的绘图表面,因此SurfaceView的UI就可以在一个独立的线程中进行行绘制。又由于不占用主线程资源,SurfaceView一方面可以实现复杂而高效的UI,另一方面又不会导致用户输入得不到及时响应。

普通的Android控件,例如TextView、Button和CheckBox等,它们都是将自己的UI绘制在宿主窗口的绘图表面之上,这意味着它们的UI是在应用程序的主线程中进行绘制的。由于应用程序的主线程除了要绘制UI之外,还需要及时地响应用户输入,否则的话,系统就会认为应用程序没有响应了,因此就会弹出一个ANR对话框出来。对于一些游戏画面,或者摄像头预览、视频播放来说,它们的UI都比较复杂,而且要求能够进行高效的绘制,因此,它们的UI就不适合在应用程序的主线程中进行绘制。这时候就必须要给那些需要复杂而高效UI的视图生成一个独立的绘图表面,以及使用一个独立的线程来绘制这些视图的UI。

一般来说,每一个窗口在SurfaceFlinger服务中都对应有一个Layer,用来描述它的绘图表面。对于那些具有SurfaceView的窗口来说,每一个SurfaceView在SurfaceFlinger服务中还对应有一个独立的Layer或者LayerBuffer,用来单独描述它的绘图表面,以区别于它的宿主窗口的绘图表面。无论是LayerBuffer,还是Layer,它们都是以LayerBase为基类的,也就是说,SurfaceFlinger服务把所有的LayerBuffer和Layer都抽象为LayerBase,因此就可以用统一的流程来绘制和合成它们的UI。

注意,用来描述SurfaceView的Layer或者LayerBuffer的Z轴位置是小于用来其宿主Activity窗口的Layer的Z轴位置的,但是前者会在后者的上面挖一个“洞”出来,以便它的UI可以对用户可见。实际上,SurfaceView在其宿主Activity窗口上所挖的“洞”只不过是在其宿主Activity窗口上设置了一块透明区域。

在分析SurfaceView类的成员函数updateWindow的实现之前,我们首先介绍一些相关的成员变量的含义,其中,mSurface、mWindow、mWindowType和mRequestedType这四个成员变量是最重要的。

SurfaceView类的成员变量mSurface指向的是一个Surface对象,这个Surface对象描述的便是SurfaceView专有的绘图表面。对于一般的视图来说,例如,TextView或者Button,它们是没有专有的绘图表面的,而是与专宿主窗口共享同一个绘图表面,因此,它们就不会像SurfaceView一样,有一个专门的类型为Surface的成员变量来描述自己的绘图表面。

SurfaceView类的成员变量mWindowType描述的是SurfaceView的窗口类型,它的默认值等于TYPE_APPLICATION_MEDIA。也就是说,我们在创建一个SurfaceView的时候,默认是用来显示多媒体的,例如,用来显示视频。SurfaceView还有另外一个窗口类型TYPE_APPLICATION_MEDIA_OVERLAY,它是用来在视频上面显示一个Overlay的,这个Overlay可以用来显示视字幕等信息。

当一个SurfaceView的绘图表面的类型等于SURFACE_TYPE_NORMAL的时候,就表示该SurfaceView的绘图表面所使用的内存是一块普通的内存。一般来说,这块内存是由SurfaceFlinger服务来分配的,我们可以在应用程序内部自由地访问它,即可以在它上面填充任意的UI数据,然后交给SurfaceFlinger服务来合成,并且显示在屏幕上。在这种情况下,SurfaceFlinger服务使用一个Layer对象来描述该SurfaceView的绘图表面。当一个SurfaceView的绘图表面的类型等于SURFACE_TYPE_PUSH_BUFFERS的时候,就表示该SurfaceView的绘图表面所使用的内存不是由SurfaceFlinger服务分配的,因而我们不能够在应用程序内部对它进行操作。例如,当一个SurfaceView是用来显示摄像头预览或者视频播放的时候,我们就会将它的绘图表面的类型设置为SURFACE_TYPE_PUSH_BUFFERS,这样摄像头服务或者视频播放服务就会为该SurfaceView绘图表面创建一块内存,并且将采集的预览图像数据或者视频帧数据源源不断地填充到该内存中去。注意,这块内存有可能是来自专用的硬件的,例如,它可能是来自视频卡的。在这种情况下,SurfaceFlinger服务使用一个LayerBuffer对象来描述该SurfaceView的绘图表面。从上面的描述就得到一个重要的结论:绘图表面类型为SURFACE_TYPE_PUSH_BUFFERS的SurfaceView的UI是不能由应用程序来控制的,而是由专门的服务来控制的,例如,摄像头服务或者视频播放服务,同时,SurfaceFlinger服务会使用一种特殊的LayerBuffer来描述这种绘图表面。使用LayerBuffer来描述的绘图表面在进行渲染的时候,可以使用硬件加速,例如,使用copybit或者overlay来加快渲染速度,从而可以获得更流畅的摄像头预览或者视频播放。


0 0
原创粉丝点击