View简介
View一般在onDraw方法里面绘图,onDraw在UI主线程执行。onDraw默认只在View初始化的时候调用一遍,所以View不会自动刷新画面,一般要调用invalidate或者postInvalidate来重新执行onDraw里面的代码进行刷新画面。UI主线程一般用来渲染组件、处理组件与用户之间的交互事件,比如说按钮的点击事件、文本框的输入事件。如果的画图任务相当繁重,那么onDraw方法里面的代码要执行好长一段时间,就可能会造成UI主线程阻塞。比如,如果在绘图的同时,用户刚好点击了某个按钮,那UI主线程会怎么处理点击事件呢?肯定是在绘图完毕后再处理点击事件,因为onDraw方法跟按钮点击事件处理都是在UI主线程内操作的。这样就给用户造成按钮点击延时处理的坏体验。
因为Android只允许在UI主线程内改变UI界面绘图完毕后渲染到屏幕的实质就是改变UI界面
SurfaceView简介
Surfaceview是视图(view)的一个继承类,这个视图里内嵌了一个专门用于绘制的Surface。你可以控制这个这个Surface的格式和尺寸,Surfaceview控制这个Surface的绘制位置。
Surfaceview也可以在onDraw里面绘图,即直接在UI主线程绘图并渲染,因为Surfaceview是View的子类。我们可以考虑这样的方案:在后台线程执行繁重的绘图任务,把所有绘制的东西缓存起来;绘制完毕后,再回到UI线程,一次性把所绘制的东西渲染到屏幕上(本质:就是后台线程绘制,UI主线程渲染)
只使用View的onDraw方法是无法实现这种方案的,而Surfaceview可以实现这种方案。先看看Surfaceview的工作原理图:
surfaceView和View最本质的区别在于:
surfaceView是在一个新起的单独线程中可以重新绘制画面,而View必须在UI的主线程中更新画面。那么在UI的主线程中更新画面 可能会引发问题,比如你更新画面的时间过长,那么你的主UI线程会被你正在画的函数阻塞。那么将无法响应按键,触屏等消息。
所以基于以上,根据游戏特点,一般分成两类。
1 被动更新画面的。比如棋类,这种用view就好了。因为画面的更新是依赖于 onTouch 来更新,可以直接使用 invalidate。 因为这种情况下,这一次Touch和下一次的Touch需要的时间比较长些,不会产生影响。
2 主动更新。比如一个人在一直跑动。这就需要一个单独的thread不停的重绘人的状态,避免阻塞main UI thread。所以显然view不合适,需要surfaceView来控制。