surfaceview和view最本质的区别在于:
surfaceview是在一个新起的单独线程中可以重新绘制画面,而view必须在ui的主线程中更新画面。那么在ui的主线程中更新画面
可能会引发问题,比如你更新画面的时间过长,那么你的主ui线程会被你正在画的函数阻塞。那么将无法响应按键,触屏等消息。当使用surfaceview
由于是在新的线程中更新画面所以不会阻塞你的ui主线程。但这也带来了另外一个问题,就是事件同步。比如你触屏了一下,你需要surfaceview中
thread处理,一般就需要有一个event queue的设计来保存touch event,这会稍稍复杂一点,因为涉及到线程同步。
所以基于以上,根据游戏特点,一般分成两类。
1 被动更新画面的。比如棋类,这种用view就好了。因为画面的更新是依赖于 ontouch 来更新,可以直接使用 invalidate。
因为这种情况下,这一次touch和下一次的touch需要的时间比较长些,不会产生影响。
2 主动更新。比如一个人在一直跑动。这就需要一个单独的thread不停的重绘人的状态,避免阻塞main ui
thread。所以显然view不合适,需要surfaceview来控制。
surfaceview简介
在一般的情况下,应用程序的view都是在相同的gui线程中绘制的。这个主应用程序线程同时也用来处理所有的用户交互(例如,按钮单击或者文本输入)。
在第8章中,已经学习了如何把容易阻塞的处理移动到后台线程中。遗憾的是,对于一个view的ondraw方法,不能这样做,因为从后台线程修改一个gui元素会被显式地禁止的。
当需要快速地更新view的ui,或者当渲染代码阻塞gui线程的时间过长的时候,surfaceview就是解决上述问题的最佳选择。
surfaceview封装了一个surface对象,而不是canvas。这一点很重要,因为surface可以使用后台线程绘制。对于那些资源敏感的
操作,或者那些要求快速更新或者高速帧率的地方,例如,使用3d图形,创建游戏,或者实时预览摄像头,这一点特别有用。
独立于gui线程进行绘图的代价是额外的内存消耗,所以,虽然它是创建定制的view的有效方式–有时甚至是必须的,但是使用surface
view的时候仍然要保持谨慎。
1.
何时应该使用surfaceview?
surfaceview使用的方式与任何view所派生的类都是完全相同的。可以像其他view那样应用动画,并把它们放到布局中。
surfaceview封装的surface支持使用本章前面所描述的所有标准canvas方法进行绘图,同时也支持完全的opengl
es库。
使用opengl,你可以再surface上绘制任何支持的2d或者3d对象,与在2d画布上模拟相同的效果相比,这种方法可以依靠硬件加速(可用的时候)来极大地提高性能。
对于显示动态的3d图像来说,例如,那些使用google
earth功能的应用程序,或者那些提供沉浸体验的交互式游戏,surfaceview特别有用。它还是实时显示摄像头预览的最佳选择。
2.
创建一个新的surfaceview控件
要创建一个新的surfaceview,需要创建一个新的扩展了surfaceview的类,并实现surfaceholder.callback。
surfaceholder回调可以在底层的surface被创建和销毁的时候通知view,并传递给它对surfaceholder对象的引用,其中包含了当前有效的surface。
一个典型的surface
view设计模型包括一个由thread所派生的类,它可以接收对当前的surfaceholder的引用,并独立地更新它。