美文网首页
Android事件分发机制

Android事件分发机制

作者: ChristZc | 来源:发表于2022-07-07 16:38 被阅读0次

    初识Android点击事件

        1. 用户对屏幕的操作的事件可以划分为3种最基础的事件:ACTION_DOWN、ACTION_MOVE、ACTION_UP。

        2. 用户的ACTION_DOWN到ACTION_UP的操作可以称为一个事件序列,主要有以下两种组成:

            一: ACTION_DOWN->ACTION_UP

            二 :ACTION_DOWN->许多个ACTION_MOVE>ACTION_UP

        3. Android 的事件分发机制大体可以分为三部分:事件生产、事件分发 、事件消费。事件的生产是由用户点击屏幕产生,我们这次着重分析事件的分发和消费,因为事件分发和处理联系的过于紧密,这篇文章将把事件的分发和消费放在一起分析。

    在Activity上的事件分发和Activity PhoneView DecorView ViewGroup view 密不可分,它们的关系如下图表示:

    View树的视图结构可以用下图概括:

    事件分发主要有以下几个方法:

        1. dispatchTouchEvent(event):用于进行点击事件的分发

        2. onInterceptTouchEvent(event):用于进行点击事件的拦截   注:只有 ViewGroup才有

        3. onTouchEvent(event):用于处理点击事件

    事件的分发到处理过程大致可以用下图简单表示:

    ACTION_DOWN的事件分发处理流程图

    总结一下:

        1. 所有的dispatchTouchEvent当为true的时候则直接消费(),为false的时候则传递给上一层的onTouchEvent方法,Activity例外false它也会消费掉,当为super方法的时候则向下一层的dispatchTouchEvent传递,注意:ViewGroup由于有onInterceptTouchEvent,他会先传递到onInterceptTouchEvent!!!

        2.onInterceptTouchEvent(ViewGroup特有)为super/false时候可以向下一层传递到dispatchTouchEvent,当为true的时候,则表示要自己消化,则会传递到自身的onTouchEvent方法。

        3.所有的onTouchEvent方法,当返回为true的时候表示自己要消费(结束),当为super/false的话则传递给上一层的onTouchEvent方法。

    对ACTION_MOVE 和ACTION_UP事件的处理

        对这两种事件的处理可以总结为下面这些内容ACTION_DOWN事件在哪个控件消费了(return true), 那么ACTION_MOVE和ACTION_UP就会从上往下(通过dispatchTouchEvent)做事件分发往下传,就只会传到这个控件,不会继续往下传,通俗理解就是ACTION_DOWN哪里结束,ACTION_MOVE 和ACTION_UP就传递到哪里结束。

    View事件方法执行顺序

    先看结论:onTouchListener > onTouchEvent > onLongClickListener > onClickListener

    1. 从dispatchTouchEvent源代码中我们可以看到View会先判断是否设置了OnTouchListener,如果设置了OnTouchListener并且onTouch方法返回了true,那么onTouchEvent不会被调用。当没有设置OnTouchListener或者设置了OnTouchListener但是onTouch方法返回false则会调用View自己的onTouchEvent方法。

    2.默认点击的时间大于了500ms算是LongClick,onTouchEvent中的ACTION_UP事件处理,也会先检查有没有长按事件的监听,再执行onLongClick

    3. 在View的onTouchEvent中的case ACTION_UP中有对onClickListener的处理,感兴趣的小伙伴可以查看具体源码。

        简单总结一下 onLongClickListener 和 onClickListener的处理过程:当ACTION_DOWN到达一个view后,他会想通过handler post一个500ms消息(我称之为长按消息)给主线程,这个消息里面封装着LongClickListener的处理任务,如果在500ms之内收到了ACTION_UP事件,则首先会移除掉主线程消息队列中的长按消息,然后去执行onClickListener对Click的执行逻辑,因为主线程中长按消息已经被移除,所以500ms后不会执行LongClick的任务。

    ViewGroup分发中有一种特殊情况,那就是FLAG_ DISALLOW_ INTERCEPT 标记位,这个标记位是通过requestDisallowInterceptTouchEvent 方法来设置的,一般用于子 View中。FLAG_DISALLOW_INTERCEPT 一旦设置后,ViewGroup 将无法拦截除了 ACTION_ DOWN以外的其他点击事件。为什么说是除了ACTION_ DOWN以外的其他事 件呢?这是因为ViewGroup在分发事件时,如果是ACTION DOWN就会重置 FLAG_ DISALLOW_ INTERCEPT这个标记位,将导致子View中设置的这个标记位无效。 因此,当面对ACTION_DOWN事件时,ViewGroup总是会调用自己的onInterceptTouchEvent方法来询问自己是否要拦截事件,这一点从源码中也可以看出来。

    注:有个TouchTarget类,观察TouchTarget的字段可以发现,TouchTarget里面存有消费事件的View,它的结构是一个链表结构。

    TouchTarget.java

    // 观察TouchTarget的字段可以发现吗,TouchTarget里面存有消费事件的View,

    //pointerIdBits(和多点触碰有关),还有指向下一个节点的引用

      private static final class TouchTarget {

            private static final int MAX_RECYCLED = 32;

            private static final Object sRecycleLock = new Object[0];

            private static TouchTarget sRecycleBin;

            private static int sRecycledCount;

            public static final int ALL_POINTER_IDS = -1; // all ones

            // The touched child view.

            @UnsupportedAppUsage

            public View child;

            // The combined bit mask of pointer ids for all pointers captured by the target.

            public int pointerIdBits;

            // The next target in the target list.

            public TouchTarget next;

    写这个博客的时候参考很多优秀的博客和书籍,在这里向各位作者表示感谢!

    相关文章

      网友评论

          本文标题:Android事件分发机制

          本文链接:https://www.haomeiwen.com/subject/lhmybrtx.html