前言

很快乐遇见你~

事件散发系列文章曾经到最初一篇了,先来回顾一下后面四篇,也当个目录:

  • Android事件散发机制一:事件是如何达到activity的? : 从window机制登程剖析了事件散发的整体流程,以及事件散发的真正终点
  • Android事件散发机制二:viewGroup与view对事件的解决 : 源码剖析了viewGroup和view是如何散发事件的
  • Android事件散发机制三:事件散发工作流程 : 剖析了触摸事件在控件树中的散发流程模型
  • Android事件散发机制四:学了事件散发有什么用? : 从实战的角度分析事件散发的使用

本文是最初一篇,次要是模仿面试状况提出一些问题以及解答,也当是整个事件散发常识的回顾。读者也能够尝试一下看看这些问题是否都能解答进去。

面试开始

  1. 学过事件散发吗,聊聊什么是事件散发

    事件散发是将屏幕触控信息分发给控件树的一个套机制。
    当咱们触摸屏幕时,会产生一些列的MotionEvent事件对象,通过控件树的管理者ViewRootImpl,调用view的dispatchPointerEvnet办法进行散发。
  2. 那次要的散发流程是什么:

    在程序的主界面状况下,布局的顶层view是DecorView,他会先把事件交给Activity,Activity调用PhoneWindow的办法进行散发,PhoneWindow会调用DecorView的父类ViewGroup的dispatchTouchEvent办法进行散发。也就是Activity->Window->ViewGroup的流程。ViewGroup则会向上来寻找适合的控件并把事件分发给他。
  3. 事件肯定会通过Activity吗?

    不是的。咱们的程序界面的顶层viewGroup,也就是decorView中注册了Activity这个callBack,所以当程序的主界面接管到事件之后会先交给Activity。
    然而,如果是另外的控件树,如dialog、popupWindow等事件流是不会通过Activity的。只有本人界面的事件才会经Activity。
  4. Activity的散发办法中调用了onUserInteraction()办法,你能说说这个办法有什么作用吗?

    好的。这个办法在Activity接管到down的时候会被调用,自身是个空办法,须要开发者本人去重写。
    通过官网的正文能够晓得,这个办法会在咱们以任意的形式开始与Activity进行交互的时候被调用。比拟常见的场景就是屏保:当咱们一段时间没有操作会显示一张图片,当咱们开始与Activity交互的时候可在这个办法中勾销屏保;另外还有没有操作自动隐藏工具栏,能够在这个办法中让工具栏从新显示。
  5. 后面你讲到最初会散发到viewGroup,那么viewGroup是如何散发事件的?

    viewGroup处理事件信息分为三个步骤:拦挡、寻找子控件、派发事件。

    事件散发中有一个重要的规定:一个触控点的一个事件序列只能给一个view解决,除非异常情况。所以如果viewGroup生产了down事件,那么子view将无奈收到任何事件。

    viewGroup第一步会判读这个事件是否须要分发给子view,如果是则调用onInterceptTouchEvent办法判断是否要进行拦挡。
    第二步是如果这个事件是down事件,那么须要为他寻找一个生产此事件的子控件,如果找到则为他创立一个TouchTarget。
    第三步是派发事件,如果存在TouchTarget,阐明找到了生产事件序列的子view,间接分发给他。如果没有则交给本人解决。

  6. 你后面讲到“一个触控点的一个事件序列只能给一个view解决,除非异常情况”,这里有什么异常情况呢?如果产生异常情况该如何解决?

    这里的异常情况次要有两点:1.被viewGroup拦挡,2.呈现界面跳转等其余状况。

    当事件流中断时,viewGroup会发送一个ACTION_CANCEL事件给到view,此时须要做一些状态的复原工作,如终止动画,复原view大小等等。

  7. 那既然说到ACTION_CANCEL类型,那你能够说说还有什么事件类型吗?

    除了ACTION_CANCEL,其余事件类型还有:

    • ACTION_MOVE:当咱们手指在屏幕上滑动时产生此事件
    • ACTION_UP:当咱们手指抬起时产生此事件

    此外多指操作也比拟常见:

    • ACTION_POINTER_DOWN: 当曾经有一个手指按下的状况下,另一个手指按下会产生该事件
    • ACTION_POINTER_UP: 多个手指同时按下的状况下,抬起其中一个手指会产生该事件。

    一个残缺的事件序列是从ACTION_DOWN开始,到ACTION_UP或者ACTION_CANCEL完结。
    一个手指的残缺序列是从ACTION_DOWN/ACTION_POINTER_DOWN开始,到ACTION_UP/ACTION_POINTER_UP/ACTION_CANCEL完结。

  8. 哦?说到多指,那你晓得ViewGroup是如何将多个手指产生的事件精确分发给不同的子view吗

    这个问题的关键在于MotionEvent以及ViewGroup外部的TouchTarget。

    每个MotionEvent中都蕴含了以后屏幕所有触控点的信息,他的外部用了一个数组来存储不同的触控id所对应的坐标数值。

    当一个子view生产了down事件之后,ViewGroup会为该view创立一个TouchTarget,这个TouchTarget就蕴含了该view的实例与触控id。这里的触控id能够是多个,也就是一个view可承受多个触控点的事件序列。

    当一个MotionEvent到来之时,ViewGroup会将其中的触控点信息拆开,再别离发送给感兴趣的子view。从而达到精准发送触控点信息的目标。

  9. 那view反对解决多指信息吗?

    View默认是不反对的。他在获取触控点信息的时候并没有传入触控点索引,也就是获取的是MotionEvent外部数组中的第一个触控点的信息。多指须要咱们本人去重写办法反对他。
  10. 嗯嗯...那View是如何解决触摸事件的?

    首先,他会判断是否存在onTouchListener,存在则会调用他的onTouch办法来处理事件。如果该办法返回true那么就散发完结间接返回。而如果该监听器为null或者onTouch办法返回了false,则会调用onTouchEvent办法来处理事件。

    onTouchEvent办法中反对了两种监听器:onClickListener和onLongClickListener。View会依据不同的触摸状况来调用这两个监听器。同时进入到onTouchEvent办法中,无论该view是否是enable,只有是clickable,他的散发办法都是返回true。

    总结一下就是:先调用onTouchListener,再调用onClickListener和onLongClickListener。

  11. 你后面屡次讲到散发办法和返回值,那你能够讲讲次要有什么办法以及他们之间的关系吗?

    嗯嗯。外围的办法有三个:dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent。

    简略来说:dispatchTouchEvent是外围的散发办法,所有散发逻辑都在这个办法中执行;onInterceptTouchEvent在viewGroup负责判断是否拦挡;onTouchEvent是生产事件的外围办法。viewGroup中领有这三个办法,而view没有onInterceptTouchEvent办法。

    • viewGroup

      1. viewGroup的dispatchTouchEvent办法接管到事件音讯,首先会去调用onInterceptTouchEvent判断是否拦挡事件

        • 如果拦挡,则调用本身的onTouchEvent办法
        • 如果不拦挡则调用子view的dispatchTouchEvent办法
      2. 子view没有生产事件,那么会调用viewGroup自身的onTouchEvent
      3. 下面1、2步的处理结果为viewGroup的dispatchTouchEvent办法的处理结果,没有生产则返回false并返回给上一层的onTouchEvent解决,如果生产则散发完结并返回true。
    • view

      1. view的dispatchTouchEvent默认状况下会调用onTouchEvent来处理事件,返回true示意生产事件,返回false示意没有生产事件
      2. 第1步的后果就是dispatchTouchEvent办法的处理结果,胜利生产则返回true,没有生产则返回false并交给上一层的onTouchEvent解决

    简略来说,在控件树中,每个viewGroup在dispatchTouchEvent办法中一直往下散发寻找生产的view,如果底层的view没有生产事件则会一层层网上调用viewGroup的onTouchEvent办法来处理事件。

    同时,因为Activity继承了Window.CallBack接口,所以也有dispatchTouchEvent和onTouchEvent办法:

    1. activity接管到触摸事件之后,会间接把触摸事件分发给viewGroup
    2. 如果viewGroup的dispatchTouchEvent办法返回false,那么会调用Activity的onTouchEvent来处理事件
    3. 第1、2步的处理结果就是activity的dispatchTouchEvent办法的处理结果,并返回给下层
  12. 看来你对事件散发理解得挺多的,那你在理论中有使用到事件散发吗?

    嗯嗯,有的。举两个例子。

    第一个需要是要设计一个按钮块,按下的时候会放大高度变低同时变得半透明,放开的时候又会回弹。这个时候就能够在这个按钮的onTouchEvent办法中判断事件类型:down则开启按下动画,up则开启开释动画。同时留神接管到cancel事件的时候要复原状态。

    第二个是滑动抵触。解决滑动抵触的外围思路就是把滑动事件依据具体的状况分发给viewGroup或者外部view。次要的办法有内部拦截法和外部拦截法。
    内部拦截法的思路就是在viewGroup中判断滑动的状况,对合乎本身滑动的事件进行拦挡,对不合乎的事件不拦挡,给到外部view。外部拦截法的思路要求viewGroup拦挡除了down事件以外的所有事件,而后再外部view中判断滑动的状况,对合乎本身滑动状况的工夫设置禁止拦挡标记,对不合乎本身滑动状况的事件则勾销标记让viewGroup进行拦挡。

  13. 那内部和外部拦截法该如何抉择呢?

    在个别的状况下,内部拦截法不须要对子view进行办法重写,比外部拦截法更加简略,举荐应用内部拦截法。

    但如果须要在子view判断更多的触摸状况时,则应用外部拦截法可更加办法子view解决状况。

  14. 后面始终聊到触摸事件,那你晓得一个触摸事件是如何从触摸屏幕开始产生的吗?

    额....在屏幕接管到触摸信息后,会把这个信息交给InputServiceManager去解决,最初通过WindowManagerService找到合乎的window,并把触摸信息发送给viewRootImpl,viewRootImpl通过层层封和解决之后,产生一个MotionEvent事件分发给view。
  15. 能够具体讲讲后面IMS解决的流程吗?

    啊。。这。。。嗯。。。。不会。。。
  16. 你还有什么想问的吗?

    可不可以。。。。给我个小小的点赞再走?
  17. 下次肯定。

    =_=....

最初

对于面试,我始终保持的一个观点就是:能够面向面试知识点学习,但不可面向面试题目答案学习 。把相干热门题目的答案背诵下来能够忽悠到一些面试官,但当初基本上都不是简略的询问什么是事件散发,而会给一个具体的需要让咱们思考等等。背诵面试题短期可能会让咱们如同学到了很多,但事实上,咱们什么都没学到。

事件散发系列文章到此完结。有疑难欢送评论区交换,心愿文章对你有帮忙~

都看到这了,要不给作者留下个点赞再走(:

全文到此,原创不易,感觉有帮忙能够点赞珍藏评论转发。
笔者满腹经纶,有任何想法欢送评论区交换斧正。
如需转载请评论区或私信交换。

另外欢迎光临笔者的集体博客:传送门