Android并发编程高级面试题汇总最全最细面试题讲解持续更新中👊👊 👀你想要的面试题这里都有👀 👇👇👇
事件分发机制是什么过程?
这道题想考察什么?
这道题想考察同学对事件分发的流程是否掌握了。
考生应该如何回答
Android事件分发是一个老生常谈的知识点。日常开发和求职过程中,都会碰到Android事件分发的问题。
Android的控件分为两类,ViewGoup和View。ViewGroup是控件的容器,可以包含多个子控件。View是控件的最小单位,它不能包裹其它的View。Android的ViewGroup对应的数据结构是树。
网上的事件分发的文章大多数是用线性的思维去分析控件树的事件遍历,我深以为不妥,经常让读者云里雾里,只见树木不见森林。
本文将以树的深度遍历方式来讲解DOWN事件的分发流程,以单链表的线性遍历方式讲解MOVE、UP事件的分发流程。
本文大纲
-
Android控件对应的多叉树
-
手势事件类型
-
事件分发涉及到的方法
-
DOWN事件的分发流程
-
MOVE、UP事件的分发流程
-
CANCEL事件触发时机以及分发流程
1. Android控件对应的多叉树
假设我们有一个这样的场景
屏幕上有一个FrameLayout名叫vp1。vp1有三个子控件vp2、vp3、vp4,它们的类型是FrameLayout。vp2有三个子控件v1、v2、v3。vp3有三个子控件v4、v5、v6。vp4有三个子控件v7、v8、v9。子控件的类型都是View。为了方便起见我们假设这些控件都是铺满屏幕的。我们将vp1控件树翻译成多叉树。
解释一下树节点ft的含义
ft的是ViewGroup类中的mFirtstTouchTarget成员变量的简称。它对应的数据结构是单链表。当DOWN事件在onTouchEvent方法中返回true,会回溯设置父View的ft指针。
举个例子
当DOWN事件从vp1开始分发。 假设DOWN事件在v7的onTouchEvent方法中返回true。 那么v7的父控件vp4的ft会指向v7(可以这样简单理解,实际上指向的是v7封装的一个TouchTarget对象)。同理vp1的ft会指向vp4。所以就生成了一条vp1->vp4->v7的分发路径。这很重要。
DOWN事件的分发是从vp1开始,假设所有的ViewGroup都不拦截事件,所有的View都不处理事件。事件会沿着最后一个子控件做深度遍历分发。以下用intercept代替onInterceptTouchEvent,touch代替onTouchEvent。
调用流程如下
vp1(intercept) -> vp4(intercept) -> v9(touch) -> v8(touch) ->v7 (touch) -> vp4(touch)-> vp3 -> v6(touch) -> v5(touch) -> v4(touch) -> vp3(touch)-> vp2 -> v3(touch) -> v2(touch) -> v1(touch) -> vp2(touch)-> vp1(touch)
这只是DOWN事件分发的一个Case。根据是否拦截,View是否处理事件。它的遍历路径也会不一样。
MOVE、UP事件分发也是从vp1开始,不同于DOWN事件的深度遍历方式,它们是通过ft的分发路径线性遍历。深度遍历是比较耗时的。如果vp1有后代View分发了事件。那么必然会通过ft生成一条分发路径。MOVE事件只需沿着分发路径线性分发就可以了。还是用上面的例子。如果v7分发了DOWN事件。那么MOVE、UP事件的分发即vp1(intercept) -> vp4(intercept) -> v7(touch)
2. 手势事件类型
本文主要讲解四种事件类型,DOWN、MOVE、UP、CANCEL。用户划动手机屏幕然后离开。Android系统首先会触发DOWN事件,紧接着一连串的MOVE事件,以UP事件收场。注意:触摸屏幕,事件之间没有任何依赖。有可能只有其中一种事件被分发。也有可能有多种事件类型被分发
| 事件类型 | 解释 |
|---|---|
| ACTION_DOWN | 手指按下屏幕 |
| ACTION_MOVE | 手指划动屏幕 |
| ACTION_CANCEL | 事件被取消 |
| ACTION_UP | 手指离开屏幕 |
3. 事件分发涉及到的方法
| 方法名 | 解释 |
|---|---|
| dispatchTouchEvent | 事件分发逻辑 |
| onInterceptTouchEvent | 是否拦截事件 (ViewGroup专属) |
| onTouchEvent | 是否处理事件 |
-
dispatchTouchEvent方法是Android系统内部实现的事件分发逻辑。返回值为boolean类型。true表示该View或ViewGroup处理了事件,反之返回false。返回值含义同onTouchEvent的返回值。dispatchTouchEvent与onTouchEvent的区别在于,默认情况下前者的返回值依赖于后者的返回值,而且前者的侧重点在于制定事件分发的流程,后者的侧重点在于View或者ViewGroup是否处理该事件。
-
onInterceptTouchEvent方法是ViewGroup专属的方法。当返回值为true表示ViewGroup(假设vp1)需要拦截掉该事件。这里有两种情况
2.1 处理DOWN事件时,如果onInterceptTouchEvent返回值为true,那么事件会直接交给vp1的onTouchEvent处理,如果返回false,交由vp1的最后一个View处理。
2.2 处理MOVE、UP事件时,如果vp1.ft为null,此时不会调用vp1的onInterceptTouchEvent方法。如果vp.ft不为null而且vp1的onInterceptTouchEvent方法返回true,那么将会在vp1处生成CANCEL事件交由vp4分发,先后置空vp4,vp1的ft对象,接下来的MOVE、UP事件只会调用vp1的onTouchEvent方法。
-
onTouchEvent方法返回值同dispatchTouchEvent方法。如果DOWN事件在某个View的onTouchEvent方法中返回true,那么其它的View的onTouchEvent将没有被执行的机会,换句话说对于同一次事件分发有且仅有一个控件能够处理事件。只有DOWN事件的返回值才有意义。其它类型事件的返回值并不会影响事件分发的流程。我们以v8的onTouchEvent的DOWN事件返回值为例。
3.1. v8 DOWN事件返回true。表示v8处理该事件。在v8分发事件之前应该是 vp1(onInterceptTouchEvent) -> vp4(onInterceptTouchEvent) -> v9(onTouchEvent)-> v8(onTouchEvent)。此时v8返回true。系统会中断vp4的child遍历(不再将事件交由v7分发)。向上回溯设置vp4的ft指向v8,vp1的ft指向vp4。
3.2. v8 DOWN事件返回false。事件继续交由v8的亲兄弟v7分发。
4.DOWN事件的分发流程
DOWN事件分发到vp1,会调用vp1的onInterceptTouchEvent。这里有拦截和不拦截两种情况。
- 如果返回true,vp1拦截DOWN事件,DOWN事件直接交由vp1的onTouchEvent处理。
- 如果返回false,vp1不拦截DOWN事件,DOWN事件将会交由vp1的最后一个子View分发。即交由vp4分发。
拦截方法以此类推,如果vp4不拦截DOWN事件,将交由v9分发事件。因为v9是View类型。没有拦截方法,所以会直接调用v9的onTouchEvent方法。该方法有处理和不处理两种情况。
- 如果返回false,v9不处理事件。那么事件继续向前分发交由v8分发,同理调用v8的onTouchEvent方法,v8不处理事件,继续交由v7处理。v7也不处理,vp4的子View到此遍历完成。此时vp4的ft为空,直接调用vp4的onTouchEvent方法。
- 如果返回true,v9处理事件。系统会中断vp4的子View遍历,DOWN事件分发结束。同时往上递归回溯设置父View的ft对象。vp4的ft指向v9,vp1的ft指向vp4。
小结:DOWN事件是通过深度遍历分发事件的。
5. MOVE、UP事件的分发流程
MOVE事件分发到VP1。它与DOWN事件的区别是,它并不一定会调用onInterceptTouchEvent。它只有当vp1的ft不为空时才会调用onInterceptTouchEvent方法,否则会直接拦截掉事件。
- 当vp1的ft为空。直接拦截掉MOVE事件。调用VP1的onTouchEvent方法,注意这里onTouchEvent方法的返回值不会影响事件分发的流程。
- 当vp1的ft不为空(当有后代View的onTouchEvent方法返回了true)。调用onInterceptTouchEvent方法,如果返回true,同上,直接调换用VP1的onTouchEvent方法。如果返回false,会通过ft的单链表线性分发事件。
UP事件同MOVE事件。这里就不分析了。
小结:MOVE、UP事件是通过线性遍历分发的。
6. CANCEL事件触发时机以及分发流程
前面我们讲到的DOWN、MOVE、UP事件都是由手触摸屏幕产生的。并没有讲到CANCEL是如何产生的。CANCEL不是由手触摸屏幕产生的。它是由系统生成。并且分发给View的。有一种场景会触发系统产生CANCEL事件。 还是上面的控件树。假设手机在屏幕的上半部分,所有的ViewGroup都不拦截事件,V9处理DOWN事件,当划动到屏幕的下半部分时,VP1拦截MOVE事件。当手指从上划动到下面时。系统将在vp1处,产生一个CANCEL事件,交由vp4分发。CANCEL事件的分发也是通过ft线性分发。当ViewGroup分发CANCEL事件后,会将ViewGroup的ft置为空。即将VP1,VP4的ft置为空。
更多Android面试题 可以详细Vx关注公众号:Android老皮 解锁 《2023最新Android中高级面试题汇总+解析》
目录
第一章 Java方面
- Java基础部分
- Java集合
- Java多线程
- Java虚拟机
第二章 Android方面
- Android四大组件相关
- Android异步任务和消息机制
- Android UI绘制相关
- Android性能调优相关
- Android中的IPC
- Android系统SDK相关
- 第三方框架分析
- 综合技术
- 数据结构方面
- 设计模式
- 计算机网络方面
- Kotlin方面
第三章 音视频开发高频面试题
- 为什么巨大的原始视频可以编码成很小的视频呢?这其中的技术是什么呢?
- 怎么做到直播秒开优化?
- 直方图在图像处理里面最重要的作用是什么?
- 数字图像滤波有哪些方法?
- 图像可以提取的特征有哪些?
- 衡量图像重建好坏的标准有哪些?怎样计算?
第四章 Flutter高频面试题
- Dart部分
- Flutter部分
第五章 算法高频面试题
- 如何高效寻找素数
- 如何运用二分查找算法
- 如何高效解决雨水问题
- 如何去除有序数组的重复元素
- 如何高效进行模幂运算
- 如何寻找最长回文子串
第六章 Andrio Framework方面
- 系统启动流程面试题解析
- Binder面试题解析
- Handler面试题解析
- AMS面试题解析