事件传递
Android中的事件在表现形式上有很多,如onTouch、onClick和onLongClick等,在具体微观上的表现形势有action_down、action_move和action_up等。
无论哪种事件表现类型,首先都是基于事件的传递模型。其实Android中的事件传递有点类似于JS中事件传递模型。都是基于先捕获然后冒泡的形式。
在OGEngine的API中,OGEngine负责捕获触摸事件,如果我们需要监听触摸事件,则需要向Scene注册。
- mScene.registerTouchArea(touchArea);
复制代码
通过查阅ITouchArea的源码发现
- public boolean contains(final float pX, final float pY);
- public float[] convertSceneToLocalCoordinates(final float pX, final float pY);
- public float[] convertLocalToSceneCoordinates(final float pX, final float pY);
- public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY);
复制代码
一个区域里有自己的判断当前触摸的坐标是不是属于自己感兴趣的,如果不是则直接抛弃。
因为Shape类是实现了ITouchArea接口的,所以我们的Sprite等精灵类都可以直接被注册。
在Scene的源码里可以找到相关的代码,于是我们了解了,在Andengine中,监听触摸和Entity并不是同一个概念,两者是独立的,于是这也解释了,为什么在Scene中detach了一个Entity,在其注册过监听的地方触摸还是会触发和以前一样的效果。
再来关注事件的传递,在源码中我们发现由于事件需要Area本身来判断其是否属于Area,所以在注册的时候并不存在类似Android中的父子关系,传递是根据注册的顺序一个一个进行的,但是相同的是如果一个Area宣布自己处理了时间(返回了true),传递序列就会直接终止,这里和Android中的事件是一样的。
但是这样固定的顺序会有一些问题,其实设计者已经考虑到了这个问题,于是我们在源码中发现了一个标志量:mOnAreaTouchTraversalBackToFront。 这个标志会决定当前事件的传递是正序还是逆序,这样就在一定程度上解决了我们的问题。
屏幕事件
OnAreaTouchListener的注册
- BaseGameActivity.onLoadEngine():生成引擎,设置引擎的参数
- BaseGameActivity.startScene():跳转到某个场景中
复制代码
其中会调用setOnTouchListener(),将Engine作为TouchListener注册到scene中。其后所有的屏幕事件就会知道调用Engine的onTouch()方法。
屏幕事件的预处理
Android中的屏幕事件是即时突发,也就是说只要产生了屏幕事件就会在事件线程内直接调用注册监听器的onTouch()方法,如果处理时间过长,Android会直接将程序判定为无响应,并被踢出来。在OGEngine中支持两种响应方式
*即时触发:接受到屏幕事件后立即调用注册的监听器(默认)
优点:和Android一样,容易学习
缺点:需要注意处理时间,超时的话会被判定为无响应
容易与OGEngine中的UpdateThread线程或描画线程形成资源竞争
为了避免竞合,又要做线程安全麻烦,比较复杂
*UpdateThread中触发:接受到屏幕事件后先放入池中,在UpdateThread中统一调用和上面的相反
预处理Flow
Engine.onTouch():判断引擎是否运行中,如果已停止就什么也不做,否则交给mTouchController处理。
SingleTouchControler.onHandleMotionEvent():有两个分支
* 即时触发:
TouchEvent.obtain():生成TouchEvent
mTouchEventCallback.onTouchEvent():响应事件(调用Engine.onTouchEven
*UpdateThread中触发:
TouchEvent.obtain():生成TouchEvent
mTouchEventRunnablePoolUpdateHandler.obtainPoolItem():生成事件处理对象
事件处理对象就是在run()方法中通过mTouchEventCallback.onTouchEvent()响应事件
touchEventRunnablePoolItem.set(touchEvent):设定屏幕事件
mTouchEventRunnablePoolUpdateHandler.postPoolItem:放入事件池中
Engine.onUpdate中调用mTouchController.onUpdate()执行事件处理
屏幕事件处理
a) Engine.onTouchEvent():屏幕事件处理入口
b) Camera.convertSurfaceToSceneTouchEvent():坐标变换
c) Engine.onTouchScene():处理Scene屏幕事件(遍历注册的TouchArea,找到合适的就调用对应的处理监听器,如果没有就调用Scene的监听器Scene的屏幕处理中有三个比较有意思的属性:
mOnAreaTouchTraversalBackToFront:事件的响应顺序是从后往前,还是调过来。默认是从后往前
mTouchAreaBindingEnabled:当监听到ACTION_DOWN事件后是否需要绑定。绑定的意思是说到ACTION_UP或ACTION_CANCEL为止的事件全部交给这个监听器处理。
mOnSceneTouchListenerBindingEnabled:和上一次差不多,这笔绑定的对象是Scene的监听器
http://www.eoeandroid.com/forum-863-1.html
OGEngine学习笔记--- 事件传递