天天看点

Android开发之SurfaceView

如果做游戏或者视频相关开发的时候,将会用到surfaceview。对于surfaceview,首先需要了解一下它自己的位置:

<a target="_blank">java.lang.object</a>

<a target="_blank">android.view.view</a>

android.view.surfaceview

由手册可知:

surfaceview是view类的继承类,这个view里内嵌了一个专门用于绘制的surface,这个可以类似的理解成为一个在view里的canvas。你可以控制这个surface的格式和尺寸。surfaceview类则控制这个surface在屏幕上的正确位置。

《android高级编程》里这样说:

在一般情况下,应用程序的view都是在相同的gui线程中绘制的。这个主应用程序线程同时也用来处理所有的用户交互(例如按钮单击或者文本输入)。

对于一个view的ondraw()方法,不能够满足将其移动到后台线程中去。因为从后台线程修改一个gui元素会被显式地禁止的。

当需要快速地更新view的ui,或者当前渲染代码阻塞gui线程的时间过长的时候,surfaceview就是解决上述问题的最佳选择。surfaceview封装了一个surface对象,而不是canvas。这一点很重要,因为surface可以使用后台线程绘制。对于那些资源敏感的操作,或者那些要求快速更新或者高速帧率的地方,例如使用3d图形,创建游戏,或者实时预览摄像头,这一点特别有用。

1. 何时应该使用surfaceview

surfaceview使用的方式与任何view所派生的类都是完全相同的。可以像其他view那样应用动画,并把它们放到布局中。

surfaceview封装的surface支持所有标准的canvas方法进行绘图,同时也支持完全的opengl es 库。

使用opengl,你可以在surface上绘制任何支持2d或者3d对象,与在2d画布上模拟相同的效果相比,这种方法可以依靠硬件加速(可用的时候)来极大地提高性能。

对于显示动态的3d图像来说,例如,那些使用google earth 功能的应用程序,或者那些提供沉浸体验的交互式游戏,surface特别有用。它还是实时显示摄像头预览的最佳选择。

2. 创建一个新的surfaceview控件

创建一个新的surfaceview控件需要创建一个新的扩展了surfaceview的类,并实现surfaceholder.callback。

surfaceholder回调可以在底层的surface被创建和销毁的时候通知view,并传递给它surfaceholder对象的引用,其中包含了当前有效的surface。

一个典型的surfaceview 设计模型包括一个由thread所派生的类,它可以接收对当前的surfaceholder的引用,并独立地更新它。

3. 使用surfaceview创建3d控件

android完全支持opengl es 3d 渲染框架,其中包含了对设备的硬件加速的支持。surfaceview控件提供了一个表面,可以在它上面渲染你的opengl场景。

那么我们在使用的时候可以这样使用:

被动更新画面的。比如棋类,这种用view就好了。因为画面的更新是依赖于 ontouch 来更新,可以直接使用 invalidate。 因为这种情况下,这一次touch和下一次的touch需要的时间比较长些,不会产生影响。

主动更新。比如一个人在一直跑动。这就需要一个单独的thread不停的重绘人的状态,避免阻塞main ui thread。所以显然view不合适,需要surfaceview来控制。

可以直接从内存或硬件设备比如相机等取得图像数据,是个非常重要的绘图容器。

它的特性是:可以在主线程之外的线程中向屏幕绘图。这样可以避免画图任务繁重的时候造成主线程阻塞,从而提高了程序的反应速度。

如何去使用一个surfaceview:

首先继承surfaceview并实现surfaceholder.callback接口。因为使用surfaceview 有一个原则,所有的绘图工作必须得在surface 被创建之后才能开始。可以被直接复制到显存从而显示出来,这使得显示速度会非常快,而在surface 被销毁之前必须结束。所以callback 中的surfacecreated 和surfacedestroyed 就成了绘图处理代码的边界。

需要重写的方法

(1)public void surfacechanged(surfaceholder holder,int format,int width,int height){}

//在surface的大小发生改变时激发

(2)public void surfacecreated(surfaceholder holder){}

//在创建时激发,一般在这里调用画图的线程。

(3)public void surfacedestroyed(surfaceholder holder) {}

//销毁时激发,一般在这里将画图的线程停止、释放。

整个过程:继承surfaceview并实现surfaceholder.callback接口 ----&gt; surfaceview.getholder()获得surfaceholder对象 ----&gt;surfaceholder.addcallback(callback)添加回调函数----&gt;surfaceholder.lockcanvas()获得canvas对象并锁定画布----&gt; canvas绘画 ----&gt;surfaceholder.unlockcanvasandpost(canvas canvas)结束锁定画图,并提交改变,将图形显示。

关于surfaceholder:

这里用到了一个类surfaceholder,可以把它当成surface的控制器,用来操纵surface。处理它的canvas上画的效果和动画,控制表面,大小,像素等。

几个需要注意的方法:

(1)、abstract void addcallback(surfaceholder.callback callback);

// 给surfaceview当前的持有者一个回调对象。

(2)、abstract canvas lockcanvas();

// 锁定画布,一般在锁定后就可以通过其返回的画布对象canvas,在其上面画图等操作了。

(3)、abstract canvas lockcanvas(rect dirty);

// 锁定画布的某个区域进行画图等..因为画完图后,会调用下面的unlockcanvasandpost来改变显示内容。

// 相对部分内存要求比较高的游戏来说,可以不用重画dirty外的其它区域的像素,可以提高速度。

(4)、abstract void unlockcanvasandpost(canvas canvas);

// 结束锁定画图,并提交改变。

测试代码如下:

转自:http://blog.csdn.net/redoffice/article/details/6722067/

继续阅读