昨天我们对View绘制三大流程源码已做了深入分析,所以关于View的绘制流程,我相信大家也有了一个大致的了解(如果不了解,请回看博文)。然而对于View,还有一个知识点,也是极其重要的,那就是View的事件分发机制(也即Android事件分发机制)。所以,今天我们就来谈谈View的事件分发机制,从源码的角度,跟随Touch事件流,走一遍流程。
在开始分析之前,我们需要了解一些概念,如一次Touch事件,可能包括下面三个事件:
- MotionEvent.ACTION_DOWN: 表示手指按下事件,一个事件的开始。
- MotionEvent.ACTION_MOVE: 表示手指移动事件,事件的持续移动。
- MotionEvent.ACTION_UP: 表示手指抬起事件,一个事件的结束。
一、View事件分发流程图
在具体分析之前,我们先来看一下事件分发流程图,以便我们更好的理解内容。图如下
二、View事件分发机制分析
由Android系统的启动,Lancher系统的启动相关知识,我们知道,当我们点击手机屏幕,主要是通过硬件传感器传输事件,传感器会将其Touch事件传给我们界面使者Activity。当事件传给Activity后,Activity会进行事件分发,会调用Activity的dispatchTouchEvent()方法进行事件分发,我们就从此方法开始来分析。我们来看具体源码
在注释1处,主要对事件进行判断,当Touch事件为MotionEvent.ACTION_DOWN事件时,会执行onUserInteraction()方法,查看源码发现,此方法是一个空方法。主要作用就是当各种事件key,touch或trackball分发到Activity时,都会执行此方法。
我们先来看注释3,当事件都没有被消费,及getWindow().superDispatchTouchEvent(ev)返回falses时,就会调用Activity自己的onTouchEvent()方法,自己对事件进行消费。
我们再来看注释2,getWindow().superDispatchTouchEvent(ev),从Activity布局加载流程源码分析(I)中,我们知道getWindow()返回的是PhoneWindow,所以我们来看看PhoneWindow中的superDispatchTouchEvent()方法
由Activity布局加载流程源码分析(I),我们也知,mDecor就是DecorView,所以我们继续来看DecorView中的superDispatchTouchEvent()方法
由DecorView绘制流程源码分析博文,我们知道,DecorView继承于FrameLayout,FrameLayout由继承于ViewGroup,ViewGroup又继承于View。通过分析相互关系,知最后调用的是ViewGroup的dispatchTouchEvent()方法(FrameLayout没有实现此方法),所以我们继续来看看ViewGroup中的方法
我们来看注释1处,事件过滤onFilterTouchEventForSecurity(),此方法为View中的方法,我们来看看此方法
这里主要就是对Window是否被遮盖进行判断,从而决定事件是否进行传递。事件要进行传递,首先就是Window没有被遮盖。我们再来看看注释2,拦截方法onInterceptTouchEvent(),此方法是ViewGroup特有的,也只有ViewGroup可以进行事件拦截。我们来看看ViewGroup的此方法
这里是直接返回了false,也就是不拦截事件。如果返回true,也就会拦截事件。在我们开发的过程中,经常会出现一些事件冲突,而往往解决这些事件冲突的途径,也都是在我们自定义的ViewGroup中复写拦截方法onInterceptTouchEvent(),重写返回值,从而解决事件冲突问题。我们继续往下走,当不拦截事件后,我们就对子View进行事件分发,这里我们继续来看注释3,方法dispatchTransformedTouchEvent()
这里主要对ViewGroup是否有子View做了一个判断,如果ViewGroup无子View,那直接调用ViewGroup父类View的dispatchTouchEvent()方法;如果有子View,那就调用子View的dispatchTouchEvent()方法;其实也都是View类的dispatchTouchEvent()方法,但这里需要注意一下,如果子View又是ViewGroup,那样当调用dispatchTouchEvent()方法时,那就调用ViewGroup的dispatchTouchEvent()事件分发方法,需要重走一遍分发流程。我们这里把子View就看成View了,所以我们就来看看此方法
从注释1处知,当事件分发到View后,首先调用的接口OnTouchListener的实现方法(在我们开发的时候,经常会对View或ViewGroup设置一些Touch的监听事件),然后才调用注释2的OnTouchEvent()方法,我们也来看看View的OnTouchEvent()方法
此方法主要是消费事件的方法,当View设置了点击事件或长按事件,那就会对事件进行消费。当手指抬起,也就是ACTION_UP事件时,就执行点击事件方法performClick(),我们也再来看看此方法
到这里,主要就是实现了View的onClickListener接口的方法onClick(),也就消费了点击事件。但如果View没有设置点击事件,那就不会消费此方法,而在ViewGroup分发事件的时候就已判断过是否有子View,此时当子View和ViewGroup都没有设置点击事件时,就会直接返回false给上一级,上一级如果也是ViewGroup,那也是类似,如果都返回false,那样事件就将会被Activity的OnTouchEvent()消费掉。
到这里,Android的事件传递我们就分析完了。
注意:
- 只要有一个View消费了ACTION_DOWN事件,剩余的所有事件(ACTION_MOVE、ACTION_UP等)都将由此View消费。
- 源码采用android-4.1.1_r1版本,建议下载源码然后自己走一遍流程,这样更能加深理解。