事件系统
事件系统分为四部分:采集信息、前期处理、WMS分配、应用程序处理。
- 采集信息:就是硬件部分收集点击的事件。
- 前期处理:对刚收集的事件进行格式处理。
- WMS 分配:WMS 记录了当前系统所有窗口完整状态信息,所以可以判断事件投递的具体进程。
- 应用程序处理:最后派发给应用程序让我们自己来处理。
1. 采集信息
采集信息基本都是硬件部分的事,无论对屏幕的触碰事件还是键盘的点击事件都是由手机硬件采集,然后保存在本地的一个事件文件里面。
2. 前期处理
在采集完信息后要做最初的事件处理,例如分类:Home、Back、Menu等。事件类型:拖动、点击、其它等。
3. WMS 分配事件
Android系统中负责管理输入事件的主要是InputManagerService(IMS)。它主要的任务就是从设备中读事件数据,然后将输入事件发送到焦点窗口中去,另外还需要让系统有机会来处理一些系统按键。
在InputManagerService
里包含了两个非常重要的工作线程。
3.1 InputReaderThread
一个独立的循环线程,主要任务就是不断地轮询相关设备节点查看是否有新的事件发生。并将事件告知派发系统。
3.2 InputDispatcherThread
一个独立的线程,用以处理从事件轮询系统告知过来的事件,保证事件的正确派发和处理。
在初始化的最初会以参数的形式将InputDispatcherThread的对象封装进InputReaderThread里,在InputReader的loopOnce循环里会不断通过Dispatcher将事件发送给Listener。
InputDispatcherThread 的一个核心工作就是确定事件的接收对象。
在WMS 和 InputDispatcher 的中间存在着一个InputMonitor对象,这个对象作为中介,工作主要分为两部分,第一:实现WindowManagerCallbacks接口,WindowManagerCallbacks包含了一些例如输入设备的配置变更,连接InputDispatcher与应用程序Socket通道,等等的接口。第二:为WMS 访问InputDispatcher提供函数实现。比如InputDispatcher中当前焦点窗口,就是WMS 通过InputMonitor来获取的。
3.2.1 通知应用程序窗口
InputDispatcher与应用程序的通信不是通过Binder来实现,而是通过管道channel来实现,就是Unix Domain Socket 实现,并且是一个双向的通道。因为重点是所有的应用程序都会在WMS里有注册,所以也只有WMS 能正确派发事件。
4. 应用程序处理
在经过InputDispatcher传入事件后,就由用户的应用程序来处理最后的事件了。
首先,我们来看下事件的分发流程。
4.1 事件分发但一直没处理
4.2 事件分发并且处理了
4.3 事件分发并且被layout消费
通过这三个图我们就可以很清楚的看到事件的分发流程顺序,并且在处理与不处理的反馈上清晰明了。
重点说下,在事件被分发到View层的时候如果同时监听了OnTouchListener
、OnClickListener
,那么很遗憾,如果在OnTouchListener消费了这个事件,那么clicklistener是无法接收这个事件的,原因就是因为在View派发消息时:
public boolean dispatchTouchEvent(MotionEvent event) {
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) {
return true;
}
return onTouchEvent(event);
}
mOnTouchListener.onTouch(this, event)
这个函数优于onTouchEvent(event)
前处理。如果想OnClickListener也可以处理也很简单,onTouch(...)返回false就行了。