android事件分发,安卓 事件分发

Android事件分发机制

Android中对视图的Touch事件进行分发处理。

员工经过长期磨合与沉淀,具备了协作精神,得以通过团队的力量开发出优质的产品。成都创新互联坚持“专注、创新、易用”的产品理念,因为“专注所以专业、创新互联网站所以易用所以简单”。公司专注于为企业提供网站建设、成都做网站、微信公众号开发、电商网站开发,重庆小程序开发公司,软件按需网站策划等一站式互联网企业服务。

单手指操作:ACTION_DOWN - ACTION_MOVE - ACTION_UP

多手指操作:ACTION_DOWN - ACTION_POINTER_DOWN - ACTION_MOVE - ACTION_POINTER_UP - ACTION_UP.

(1) dispatchTouchEvent() :事件分发

(2) onInterceptTouchEvent() :事件拦截

(3) onTouchEvent() :事件处理

ViewGroup 的相关事件有三个:onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent。

View 的相关事件只有两个:dispatchTouchEvent、onTouchEvent。

先分析ViewGroup的处理流程:首先得有个结构模型概念:ViewGroup和View组成了一棵树形结构,最顶层为Activity的ViewGroup,下面有若干的ViewGroup节点,每个节点之下又有若干的ViewGroup节点或者View节点,依次类推。如图:

点击事件达到顶级 View(一般是一个 ViewGroup),会调用 ViewGroup 的 dispatchTouchEvent 方法,如果顶级 ViewGroup 拦截事件即 onInterceptTouchEvent 返回 true,则事件由 ViewGroup 处理,这时如果 ViewGroup 的 mOnTouchListener 被设置,则 onTouch 会被调用,否则 onTouchEvent 会被调用。也就是说如果都提供的话,onTouch 会屏蔽掉 onTouchEvent。在 onTouchEvent 中,如果设置了 mOnClickListenser,则 onClick 会被调用。如果顶级 ViewGroup 不拦截事件,则事件会传递给它所在的点击事件链上的子 View,这时子 View 的 dispatchTouchEvent 会被调用。如此循环。

Android View 事件分发机制

Android 事件机制包含系统启动流程、输入管理(InputManager)、系统服务和 UI 的通信(WindowManagerService + ViewRootImpl + Window)、事件分发等一系列的环节。

Android 系统中将输入事件定义为 InputEvent,根据输入事件的类型又分为了 KeyEvent(键盘事件) 和 MotionEvent(屏幕触摸事件)。这些事件统一由系统输入管理器 InputManager 进行分发。

在系统启动的时候,SystemServer 会启动 WindowManagerService,WMS 在启动的时候通过 InputManager 来负责监控键盘消息。

InputManager 负责从硬件接收输入事件,并将事件通过 ViewRootImpl 分发给当前激活的窗口处理,进而分发给 View。

Window 和 InputManagerService 之间通过 InputChannel 来通信,底层通过 socket 进行通信。

Android Touch 事件的基础知识:

KeyEvent 对应了键盘的输入事件;MotionEvent 就是手势事件,鼠标、笔、手指、轨迹球等相关输入设备的事件都属于 MotionEvent。

InputEvent 统一由 InputManager 进行分发,负责与硬件通信并接收输入事件。

system_server 进程启动时会创建 InputManagerService 服务。

system_server 进程启动时同时会启动 WMS,WMS 在启动的时候就会通过 IMS 启动 InputManager 来监控键盘消息。

App 端与服务端建立了双向通信之后,InputManager 就能够将产生的输入事件从底层硬件分发过来,Android 提供了 InputEventReceiver 类,以接收分发这些消息:

Window 和 IMS 之间通过 InputChannel 通信。InputChannel 是一个 pipe,底层通过 socket 进行通信。在 ViewRootImpl.setView() 过程中注册 InputChannel。

Android 事件传递机制是 先分发再处理 ,先由外部的 View 接收,然后依次传递给其内层的 View,再从最内层 View 反向依次向外层传递。

三个方法的关系如下:

分发事件:

应用了树的 深度优先搜索算法 (Depth-First-Search,简称 DFS 算法),每个 ViewGroup 都持有一个 mFirstTouchTarget, 当接收到 ACTION_DOWN 时,通过递归遍历找到 View 树中真正对事件进行消费的 Child,并保存在 mFirstTouchTarget 属性中,依此类推组成一个完整的分发链。在这之后,当接收到同一事件序列的其它事件如 ACTION_MOVE、ACTION_UP 时,则会跳过递归流程,将事件直接分发给下一级的 Child。

ViewGroup 分发事件的主要的任务是找一个 Target,并且用这个 Target 处理事件,主要逻辑如下 :

为什么倒序查找 TouchTarget?

如果按添加顺序遍历,当 View 重叠时(FrameLayout),先添加的 View 总是能消费事件,而后添加的 View 不可能获取到事件。

拦截事件:

[1] Android 事件分发机制的设计与实现

[2] Android 事件拦截机制的设计与实现

Android TV 按键焦点事件分发流程详解

DecorView →PhoneWindow →Activity→ViewGroup→view

下面我们根据按键事件的分发流程,抽丝剥茧,逐一分析。

private int processKeyEvent(QueuedInputEvent q)

1、DecorView.java

2、Activity.java

3、ViewGroup.java

4、View.java

通过该方法,接收器receiver的onKeyDown、onKeyUp、onKeyLongPress、onKeyMultiple等方法将被回调。

在上述按键事件的入口中提到的ViewRootImpl中

如果mView.dispatchKeyEvent(event)返回true,则结束事件分发;

如果返回false,则调用如下方法

继续执行后续的焦点导航流程。

焦点导航的总体流程就是:

1、View focused = mView.findFocus();//从视图树的顶层,即DecorView一层一层的递归查找当前获得焦点的view

2、View v = focused.focusSearch(direction);根据导航的方向查找下一个可获取焦点的view

3、v.requestFocus(direction, mTempRect)请求获取焦点

4、v.requestFocus(direction,mTempRect)内部,调用mParent.requestChildFocus(this, focused)逐层递归向上级通知

ViewRootImpl.java

mView即DecorView,从DecorView开始,一层一层的向下递归查找当前获得焦点的view

找到了当前获得焦点的focused,调用该焦点view的focusSearch(direction)方法查找direction方向上下一个将要获取焦点的view。

focused.focusSearch(direction)实际上会调用mParent.focusSearch(this, direction)方法,层层递归,直到调用到DecorView的focusSearch(this, direction)方法。

而DecorView继承ViewGroup,实际上最终会调用到FocusFinder.getInstance().findNextFocus(this, focused, direction),this 就是DecorView对象。

最终会调用到DecorView父类ViewGroup中的FocusFinder.getInstance().findNextFocus(this, focused, direction);

ViewGroup.java

FocusFinder.java

搜索到下一个获取焦点的view后,调用该view.requestFocus(direction, mTempRect)方法

注意:调用requestFocus(direction, mTempRect)需要区分调用者。

如果是ViewGroup,则会更加焦点获取策略,实现父View和子View之间获取焦点的优先级。

如下是ViewGroup.java 和View.java 中requestFocus方法是实现:

ViewGroup.java

View.java

View获取到焦点后,会调用mParent.requestChildFocus(this, focused)逐层递归向上级通知

ViewGroup.java


本文题目:android事件分发,安卓 事件分发
URL分享:http://hbruida.cn/article/dsddjip.html