View事件分发机制

Android输入系统(一)输入事件传递流程和InputManagerService的诞生

输入系统是外界与Android设备交互的基础,仅凭输入系统是无法完成输入事件传递的,因此需要输入系统和Android系统的其他成员来共同完成事件传递。输入系统事件传递需要经过以下几个部分。

View事件分发机制_第1张图片
image

输入系统部分

输入系统部分主要又分为输入子系统和InputManagerService组成(以下简称IMS),在Android中还有一个IMS(IP Multimedia Subsystem)意为为IP多媒体子系统,不要搞混了。
Android的输入设备有很多种,比如屏幕、键盘、鼠标、游戏手柄、操纵杆等等,其中应用开发接触最多的屏幕。当输入设备可用时,Linux内核会在/dev/input中创建对应的设备节点。
用户操作这些输入设备时会产生各种事件比如按键事件、触摸事件、鼠标事件等。
输入事件所产生的原始信息会被Linux内核中的输入子系统采集,原始信息由Kernel space的驱动层一直传递到User space的设备节点。

Android提供了getevent和sendevent两个工具帮助开发者从设备节点读取输入事件和写入输入事件。


View事件分发机制_第2张图片
image

IMS所做的工作就是监听/dev/input下的所有的设备节点,当设备节点有数据时会将数据进行加工处理并找到合适的Window,将输入事件派发给它。

WMS处理部分

View事件分发机制_第3张图片
image

WMS的职责之一就是输入系统的中转站,WMS作为Window的管理者,会配合IMS将输入事件交由合适的Window来处理。

View处理部分

一般情况下,输入事件最终会交由View来处理,应用开发者就可以通过一些回调方法轻松得到这个事件的封装类并对其进行处理,比如onTouchEvent(MotionEvent ev)方法。关于View体系可以查看View体系这一系列文章。

Android View体系(五)从源码解析View的事件分发机制

1. 处理点击事件对方法
View的层级

View的结构是树形的结构,View可以放在ViewGroup中,这个ViewGroup也可以放到另一个ViewGroup中,这样层层的嵌套就组成了View的层级。

什么是点击事件分发

当我们点击屏幕,就产生了触摸事件,这个事件被封装成了一个类:MotionEvent。而当这个MotionEvent产生后,那么系统就会将这个MotionEvent传递给View的层级,MotionEvent在View的层级传递的过程就是点击事件分发。

点击事件分发的重要方法
  • dispatchTouchEvent(MotionEvent ev):用来进行事件的分发
  • onInterceptTouchEvent(MotionEvent ev):用来进行事件的拦截,在dispatchTouchEvent()中调用,需要注意的是View没有提供该方法
  • onTouchEvent(MotionEvent ev):用来处理点击事件,在dispatchTouchEvent()方法中进行调用
2. 点击事件分发的传递规则
点击事件由上而下的传递规则

当点击事件产生后会由Activity来处理再传递给Window再传递给顶层的ViewGroup,一般在事件传递中只考虑ViewGroup的onInterceptTouchEvent()方法,因为一般情况我们不会去重写dispatchTouchEvent()方法。
对于根ViewGroup,点击事件首先传递给它的dispatchTouchEvent()方法,如果该ViewGroup的onInterceptTouchEvent()方法返回true,则表示它要拦截这个事件,这个事件就会交给它的onTouchEvent()方法处理,如果onInterceptTouchEvent()方法返回false,则表示它不拦截这个事件,则交给它的子元素的dispatchTouchEvent()来处理,如此的反复下去。如果传递给最底层的View,View是没有子View的,就会调用View的dispatchTouchEvent()方法,一般情况下最终会调用View的onTouchEvent()方法。
事件由上而下传递返回值规则为:true,拦截,不继续向下传递;false,不拦截,继续向下传递。

点击事件由下而上的传递规则

点击事件传给最底层的View,如果他的onTouchEvent()方法返回true,则事件由最底层的View消耗并处理了,如果返回false则表示该View不做处理,则传递给父View的onTouchEvent()处理,如果父View的onTouchEvent()仍旧返回返回false,则继续传递给改父View的父View处理,如此的反复下去。
事件由下而上传递返回值规则为:true,处理了,不继续向上传递;false,不处理,继续向上传递。

只了解View的事件分发是不够的,来看下输入系统对事件的处理

  1. IMS启动了InputDispatcherThread和InputReaderThread,分别用来运行InputDispatcher和InputReader
  2. InputDispatcher先于InputReader被创建,InputDispatcher的dispatchOnceInnerLocked函数用来将事件分发给合适的Window。InputDispatcher没有输入事件处理时会进入睡眠状态,等待InputReader通知唤醒
  3. InputReader通过EventHub的getEvents函数获取事件信息,如果是原始输入事件,就将这些原始输入事件交由不同的InputMapper来处理,最终交由InputDispatcher来进行分发。
  4. InputDispatcher的notifyKey函数中会根据按键数据来判断InputDispatcher是否要被唤醒,InputDispatcher被唤醒后,会重新调用dispatcherOnceInnerLocked函数将输入事件分发给合适的Window


    View事件分发机制_第4张图片
    image

你可能感兴趣的:(View事件分发机制)