Android面试13-View的事件分发

Android面试13-View的事件分发

      • 分发的事件
      • View继承关系
      • 事件分发处理流程
      • 事件分发
        • 顶级View对点击事件的分发过程
      • 事件处理
        • 事件处理总结

分发的事件

首先事件分发主要分为
Android面试13-View的事件分发_第1张图片

事件分发发生在ViewGroup中的dispatchTouchEvent中

action_move会触发多次

View继承关系

Android面试13-View的事件分发_第2张图片

view中dispatchTouchEvent用来处理事件

viewgroup中dispatchTouchEvent用来分发事件,不处理事件,viewgroup直接交给view去处理事件

事件分发处理流程

Android面试13-View的事件分发_第3张图片

viewgroup先走分发流程,再走处理流程

view只走处理流程

Android面试13-View的事件分发_第4张图片

点击事件的整个分发流程大概:

首先点击事件,压到屏幕后,触发触屏,导致驱动,再到内核这一块,然后再慢慢的到安卓底层,安卓底层再到源码的话,安卓是直接先到activity的dispatchTouchEvent

Android面试13-View的事件分发_第5张图片

然后通过getWindow(window是一个抽象类,他只有一个实现类就是PhoneWindow)调用PhoneWindow的superDispatchTouchEvent方法

Android面试13-View的事件分发_第6张图片

然后会调用DecorView的superDispatchTouchEvent

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存失败,源站可能有防盗链机制,建议将图片保存下来直接上传下上传(icW18sTvnydp-1621263277875)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\1620569132632.png)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\1620569132632.png)]

然后调用父类的dispatchTouchEvent方法,这里父类是FrameLayout,但其实是调用的viewgroup的dispatchTouchEvent方法

Android面试13-View的事件分发_第7张图片

我们的activity,以及viewGroup容器,都是通过viewGroup的dispatchTouchEvent来进行分发的,然后再由view.dispatchTouchEvent进行处理

注意:

分发是从底层的view一层一层分发

Android面试13-View的事件分发_第8张图片

处理是从顶层的view一层一层往上处理的

Android面试13-View的事件分发_第9张图片

处理事件最先处理的是我们最先看到的容器,而分发流程正好相反

事件分发

刚总结完了事件处理,现在来梳理一下事件分发

我们其实可以想象我们的屏幕是一个立体坐标系

Android面试13-View的事件分发_第10张图片

首先点击事件产生时,先进入的是activity

activity的dispatchTouchEvent

Android面试13-View的事件分发_第11张图片

然后交给PhoneWindow的superDispatchTouchEvent

Android面试13-View的事件分发_第12张图片

然后再到DecorView的superDispatchTouchEvent

Android面试13-View的事件分发_第13张图片

然后调用父类的dispatchTouchEvent

DecorView是继承FrameLayout的,但是FrameLayout没有重写dispatchTouchEvent,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TWS8bv5d-1621263277880)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\1621146042215.png)]

所以就到了我们的viewgroup的dispatchTouchEvent

Android面试13-View的事件分发_第14张图片

而viewgroup是重写了父类的dispatchTouchEvent,所以可以用来进行事件分发,而事件处理是交给了父类,也就是view

super.dispatchTouchEvent -->view.dispatchTouchEvent

继续回到事件分发

顶级View对点击事件的分发过程

点击事件到达顶级View(一般是ViewGroup)以后,会调用ViewGroup的dispatchTouchEvent方法,主要逻辑是这样的,

如果顶级ViewGroup拦截事件也就是onInterceptTouchEvent返回ture,那么事件就交给ViewGroup处理,

(处理:这时如果ViewGroup的setOnTouchListener被调用的话,则OnTouch会被调用,否则OntouchEvent会被调用,也就是说都调用的情况下,onTouch会屏蔽掉onTouchEvent。在onTouchEvent中,如果设置了setOnClickListener,那么onClick会被调用,如果onTouch返回ture,那么不会调用onTouchEvent,也就不会调用onClick)

如果顶级ViewGroup不拦截事件,那么事件会传递给它所在的点击事件链上的子View,这时子View的dispatchTouchEvent会被调用,到此为止,事件已经从顶级View传递给了下一层View,接下来的传递过程和顶级View是一致的。如此循环就完成了整个事件的分发。

事件处理

我们先创建一个Button,然后通过点击事件调用button的onClick和onTouch方法

如下:

Android面试13-View的事件分发_第15张图片

在这里提出三个问题:

1.onTouch的返回值 有什么用?

2.onClick和onTouch哪个会先调用?

3.在哪里调用?

event对应事件
ACTION_DOWN             = 0;//按下
ACTION_UP               = 1;//离开
ACTION_MOVE             = 2;//滑动
ACTION_CANCEL           = 3;//事件被上层拦截

如果onTouch返回ture,会出现什么情况?onClick和onTouch方法中的日志都会打印吗?

答案如下:只有onTouch方法中log会打印,

Android面试13-View的事件分发_第16张图片

如果onTouch返回false呢?

Android面试13-View的事件分发_第17张图片

这里是onTouch和onClick都会执行,而且 注意是onTouch先执行,

—>可见onTouch的返回值决定oclick是否执行

我们的事件处理在view.dispatchTouchEvent里面,主要是在这段代码里执行

Android面试13-View的事件分发_第18张图片

最外层的if判断点击事件是否安全,一般来说我们的点击事件都是安全的。

然后判断mListenerInfo是否为空。这里我们需要看到前面的

setOnClickListener或者setOnTouchListener方法里面,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TNBjCEvQ-1621263277884)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\1621063017464.png)]

再看到getListenerInfo里面

Android面试13-View的事件分发_第19张图片

这里有一个单例模式,如果mListenerInfo不为空那么直接返回,否则创建一个mListenerInfo。

所以mListenerInfo肯定不为空。

Android面试13-View的事件分发_第20张图片

再看到li.mOnTouchListener != null这个判断。

这个地方其实在

Android面试13-View的事件分发_第21张图片

调用方法的时候就已经new好了。所以这里也是不为空的。

(mViewFlags & ENABLED_MASK) == ENABLED表示是否控件是可以点击的

然后就到了li.mOnTouchListener.onTouch(this, event),在这里执行了onTouch。

如果onTouch返回了false,result就会返回false。如果onTouch返回了true,result就会返回true。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RBloJj2R-1621263277886)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\1621064748149.png)]

然后在下面接着又有一个判断,这里的意思是result为false的话onTouchEvent就会执行,为true就不会执行

所以我们可以推测onclick方法在onTouchEvent方法里面执行

进一步推测onTouchEvent方法不一定是执行的。当onTouch返回ture,result返回ture的时候就不会。、

再回到onclick的执行,我们可以发现log日志打印,onclick是在ACTION_UP 之后执行的,所以我们可以看到switch判断下

case MotionEvent.ACTION_UP:中的

Android面试13-View的事件分发_第22张图片

看到这个PerformClick方法

Android面试13-View的事件分发_第23张图片

然后进入performClickInternal方法

Android面试13-View的事件分发_第24张图片

继续performClick方法

Android面试13-View的事件分发_第25张图片

诶,有没有一种拨开云雾见光明的感觉

playSoundEffect(SoundEffectConstants.CLICK);//对点击声音的处理

事件处理总结

总结顺序就是

dispatchTouchEvent —>onTouch —> onTouchEvent —> onClick

如果onTouch返回true,就不会继续了

你可能感兴趣的:(#,Android面试重要知识点,安卓,android)