大家在做android游戏和视频播放器的apk开发时,会经常用到SurfaceView这个类,以及它的子类VideoView,GLSurfaceView等.它与普通的View视图有本质的区别,本文就对SurfaceView的工作原理做个详细介绍(阅读本文之前,你需要对view的绘制流程,WMS,SurfaceFlinger的工作原理有一定了解).
SurfaceView不与它的宿主窗口共享同一个绘图表面,它拥有自己独立的绘图表面,也就是说拥有独立的Surface本地窗口,它可以在一个独立的子线程中进行绘制,这样它的绘制操作就不会阻塞主线程,当然它也可以在主线程中进行绘制,而其它的普通ui控件都是在应用程序的主线程中进行绘制的。
SurfaceView类的成员变量mWindowType描述的是SurfaceView的窗口类型,它的默认值等于TYPE_APPLICATION_MEDIA。也就是说,我们在创建一个SurfaceView的时候,默认是用来显示多媒体的,例如,用来显示视频。SurfaceView还有另外一个窗口类型TYPE_APPLICATION_MEDIA_OVERLAY,它是用来在视频上面显示一个Overlay的,这个Overlay可以用来显示视字幕等信息。
我们在创建了一个SurfaceView之后,可以调用它的成员函数setZOrderMediaOverlay、setZOrderOnTop或者setWindowType来修改该SurfaceView的窗口类型,也就是修改该SurfaceView的成员变量mWindowType的值。SurfaceView一般都是位于它对应的宿主窗口之下,也就是对应的layer的zorder值更小,这样便于在SurfaceView的上面显示其它ui和字幕等信息,由于SurfaceView在其宿主窗口下面,这就要求必须在其宿主窗口界面上“挖洞”来显示SurfaceView内容,挖洞的实质就是在宿主窗口界面中对应显示SurfaceView的那块区域位置设置为透明区域。设置透明区域的代码调用流程为:
ViewRootImpl::performTraversals()->DecorView::dispatchAttachedToWindow()->View::dispatchAttachedToWindow()->SurfaceView::onAttachedToWindow()。