安卓面试题(18/30)事件分发机制全解析

牛客高级系列专栏:

安卓(安卓系统开发也要掌握)


嵌入式


本人是2020年毕业于广东工业大学研究生:许乔丹,有国内大厂CVTE和世界500强企业安卓开发经验,该专栏整理本人对常见安卓高频开发面试题的理解;

网上安卓资料千千万,笔者将继续维护专栏,一杯奶茶价格不止提供答案解析,承诺提供专栏内容免费技术答疑,直接咨询即可。助您提高安卓面试准备效率,为您面试保驾护航!

正文开始⬇

事件分发机制属于安卓基础面试必问题目之一。最关键是理解事件分发三个函数的作用和返回值的含义,就基本足够应付面试了。面试官可能会问:

  1. 请介绍什么是事件分发机制,以及对应流程⭐⭐⭐⭐⭐
  2. 谈谈你对MotionEvent的认识?Cancel事件是什么情况下触发的⭐⭐⭐
  3. OnTouchListener & OnTouchEvent & OnClickListener三者之间的关系⭐⭐⭐⭐

看完以下的解析,一定可以让面试官眼前一亮。

目录

  • 1、触摸事件分发流程
  • 2、触摸事件分发的3个重要方法
  • 3、onTouch()、onTouchEvent()、onClick()傻傻分不清?
  • 4、事件分发总结
    • 4.1 表格总结
    • 4.2 伪代码表示
    • 4.3 事件由上到下的传递规则
    • 4.4 事件由下而上的传递规则

1、触摸事件分发流程

在《Activity、Window、DecorView以及ViewRoot层级关系全解析》一节有下图: alt

我们知道View的结构是树形结构,View可以放在ViewGroup中,ViewGroup也可以放在另一个ViewGroup中,如此就形成了层层嵌套的关系。当我们触摸到屏幕后,就会生成一个Touch事件,常见的Touch事件有:

  • MotionEvent.ACTION_DOWN:按下
  • MotionEvent.ACTION_MOVE:滑动
  • MotionEvent.ACTION_CANCEL:非人为原因结束本次事件
  • MotionEvent.ACTION_UP:抬起 一般来说,一个事件会经过:按下 --》 滑动 --》抬起,这三个阶段,并在这个过程中会有非人为原因结束本次触摸流程。这些事件会在代码里会封装成一个MotionEvent。那么,当MotionEvent产生后,系统就会将其传递给View树,MotionEvent在View的层级传递,并最终得到处理的过程,就是触摸事件分发流程。一个流程的传递顺序是:

Activity/Window --> ViewGroup --> View

其中,View就是各种控件,如Button、TextView等,而ViewGroup是View的子类,因此本质上也是一个View,只不过ViewGroup可以包含多个子View和定义布局参数。

2、触摸事件分发的3个重要方法

有以下3个重要方法是必须掌握的:

  • dispatchTouchEvent(MotionEvent ev):进行事件的分发,在View和ViewGroup类都有该方法,下文会对该方法的源码进行分析,需要区分清楚;
  • onInterceptTouchEvent(MotionEvent ev):进行事件拦截,在dispatchTouchEvent()中调用,在分发的过程中判断是否需要进行拦截,需要注意的是只有ViewGroup有该方法,View是没有提供该方法的。如果返回true代表拦截,返回false代表不拦截;
  • onTouchEvent(MotionEvent ev):触摸事件处理,同样在dispatchTouchEvent()方法中进行调用,如果返回true代表已处理事件,返回false代表不处理事件,事件继续传递。

为了更好的了解三者的关系,我们从源码出发,首先看看ViewGroup的dispatchTouchEvent(),源码是Android9.0.0=》/frameworks/base/core/java/android/view/ViewGroup.java:


public boolean dispatchTouchEvent(MotionEvent ev) {
    ...
    if (!disallowIntercept) {
        intercepted = onInterceptTouchEvent(ev);  //1
        ev.setAction(action); // restore action in case it was changed
    } else {
        intercepted = false;
    }
    ...
    if (actionMasked == MotionEvent.ACTION_DOWN
            || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
            || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
        ...
        if (newTouchTarget == null && childrenCount != 0) {
            ...
            for (int i = childrenCount - 1; i >= 0; i--) { //2:遍历ViewGroup的子View
                final int childIndex = getAndVerifyPreorderedIndex(
                        childrenCount, i, customOrder);
                final View child = getAndVerifyPreorderedView(
                        preorderedList, children, childIndex);

                ...
                resetCancelNextUpFlag(child);
                if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) { //3
                    ...
                    break;
                }

                ...
            }
        }
    }
}

在[注释1]调用了onInterceptTouchEvent()方法来判断是否要拦截当前的事件。

  public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (ev.isFromSource(InputDevice.SOURCE_MOUSE)
                && ev.getAction() == MotionEvent.ACTION_DOWN
                && ev.isButtonPressed(MotionEvent.BUTTON_PRIMARY)
                && isOnScrollbarThumb(ev.getX(), ev.getY())) {
            return true;
        }
        return false;
    }

可以看出onInterceptTouchEvent()默认返回false,代表不拦截。接着在[注释2]遍历ViewGroup的子View,如果子View可以接收到触摸事件,则会执行[注释3]dispatc

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

Android高频面试题全解析 文章被收录于专栏

#提供免费售后答疑!!花一杯奶茶的钱获得安卓面试答疑服务,稳赚不赔# Android发展已经很多年,安卓资料网上千千万,本专栏免费提供专栏内容技术答疑!!私聊当天必回。在阅读过程或者其他安卓学习过程有疑问,都非常欢迎私聊交流。

全部评论

相关推荐

首先还是很感谢大疆给本菜鸡提供了一个面试的机会可惜自己面得一塌糊涂面的岗位是图像算法(实习生),听面试官说是影像部门的。预期之外的一场面试,在hr打电话通知捞起来约面之时我都没想过会得到这个机会。楼主是光学专业,仅仅是在自己项目中用过相机来检测一些问题,自己是万万不敢碰瓷算法岗的,但是想着涨涨经验也好还是来面试了全程大概50分钟,自我介绍后楼主的噩梦就开始了,两位面试官细细拷打了项目中相机的使用细节,为什么不用raw图用jpg图;暗角和畸变你是怎么考虑的;世界坐标系和相机坐标系如何变换;白场校正算法是什么等等面到一半楼主已经坐立不安了人生中第一次面试就感到自己如此的菜,处于一问三不知的状态,说了非常多句“不好意思这个我不是很了解”,随后面试官应该也看出了我的窘迫,尝试问一些很基础的问题来缓和这场面试的氛围,例如canny算子求出的边缘数据结构是什么样子、怎么根据顶点坐标做变换拉伸之类的,但是楼主大脑已经一片空白,全部以道歉结束最后就问了一些常规问题,为什么要投递大疆、团队出现分歧如何解决等,随后以反问结束了面试面试已经过去了好几天,今天终于有勇气来回顾这场让我坐立难安的50分钟。回想起来还是自己准备太少、对简历细节不熟悉,以至于面试官后面主动询问我项目的难点和解决办法时我也不能讲出个所以然,最终被评价为“你这个项目太简单了点”总体来说,虽然面试前也没指望自己能进,但是面完还是怀疑人生了好几天。感谢两位温和的很有耐心的面试官,虽然项目非常不匹配,但是还是很有耐心地听我介绍,并提出了许多我根本没考虑过的问题[笑哭R]感觉整场面试就是在浪费他们一个小时时间。。
点赞 评论 收藏
分享
评论
13
27
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务