事件的产生-InputManagerService
IMS所做的工作就是监听/dev/input下的所有的设备节点,当设备节点有数据时会将数据进行加工处理并找到合适的Window,将输入事件派发给它。
Linux会为所有可用的输入设备在/dev/input目录在建立event0~n或者其他名称的设备节点,Android输入系统会监控这些设备节点,具体是通过INotify和Epoll机制来进行监控。而不是通过一个线程进行轮询查询。
- INotify是Linux内核提供的一种文件系统变化通知机制。它可以为应用程序监控文件系统的变化,如文件的新建,删除等。
- Epoll机制简单的说就是使用一次等待来获取多个描述的可读或者可写状态。这样我们不必对每一个描述符创建独立的线程进行阻塞读取,在避免了资源浪费的同时获得较快的相应速度。
Android是基于Linux系统的。当输入设备可用时(这里的输入设备包括很多设备,比如触摸屏和键盘是Android最普遍也是最标准的输入设备,另外它还包括外接的游戏手柄、鼠标等),Linux内核会为输入设置创建对应的设备节点。
我们对触摸屏进行操作时,Linux就会收到相应的硬件中断,然后将中断加工成原始的输入事件并写入相应的设备节点中。而我们的Android 输入系统所做的事情概括起来说就是监控这些设备节点,当某个设备节点有数据可读时,将数据读出并进行一系列的翻译加工,然后在所有的窗口中找到合适的事件接收者,并派发给它。
- 点击屏幕
- InputManagerService的Read线程捕获事件,预处理后发送给Dispatcher线程
Dispatcher找到目标窗口- 通过Socket将事件发送到目标窗口
- APP端被唤醒
- 找到目标窗口处理事件
当我们触摸(点击)屏幕时,Android输入系统IMS通过对事件的加工处理再合适的Window接收者并通过InputChannel向Window派发加工后的事件,并触发InputReceiver的onInputEvent的调用,由此产生后面一系列的调用,把事件派发给整个控件树的根DecorView。而DecorView又上演了一出偷梁换柱的把戏,先把事件交给Activity处理,在Activity中又把事件交还给了我们的DecorView。自此沿着控件树自上向下依次派发事件。
dispatchTouchEvent
- true: 消费事件并拦截,停止向下传递,流转到当前控件的 onTouchEvent
- false: 消费并停止向下传递,流转到上层ViewGroup或者Activity的 onTouchEvent
- super.dispatchTouchEven: 流转到当前控件的Intercept
onInterceptTouchEvent
- true: 将事件进行拦截,流转到当前view的onTouchEvent
- false: 放行,流转到子控件的dispatchTouchEvent