# Android View的事件分发 分析源码

引言

从Android底层开始分析View的事件分发至上层FrameWork。

分两部分来说:

  • 触碰屏幕传递事件至当前Activity.
  • Activtiy传递事件至触碰到的View 或者 ViewGroup

触碰屏幕传递事件至当前Activity

触摸事件是由Linux内核的一个Input子系统来管理的(InputManager),Linux子系统会在 /dev/input/ 这个路径下创建硬件输入设备节点(这里的硬件设备就是我们的触摸屏了)。当手指触动触摸屏时,硬件设备通过设备节点像内核(其实是InputManager管理)报告事件,InputManager 经过处理将此事件传给 Android系统的一个系统Service,这个Service叫WindowManagerService。之后WindowManagerService会将事件传递到PhoneWindow.

可以参考下图, WindowManagerService连接PhoneWindow的过程.

# Android View的事件分发 分析源码_第1张图片
Touch.jpg

WindowManagerService调用dispatchPointer()从存放WindowState的z-order顺序列表中找到能接收当前touch事件的 WindowState,通过IWindow代理将此消息发送到IWindow服务端(IWindow.Stub子类),这个IWindow.Stub属于ViewRoot(这个类继承Handler,主要用于连接PhoneWindow和WindowManagerService),所以事件就传到了ViewRoot.dispatchPointer()中.

看下ViewRoot.dispatchPointer method

ViewRoot_dispatchPointer.jpg

你可以看到通过用Message将DISPATCH_POINTER事件发送出去,处理事件应该在handleMessage method里.

看下ViewRoot.handleMessage method

# Android View的事件分发 分析源码_第2张图片
ViewRoot_handleMessage.jpg

看下ViewRoot.deliverPointerEvent method

# Android View的事件分发 分析源码_第3张图片
ViewRoot_deliver.jpg

最终你会发现调用mView.dispatchTouchEvent(event)
(mView是一个PhoneWindow.DecorView对象),PhoneWindow.DecorView继承FrameLayout(FrameLayout继承ViewGroup,ViewGroup继承自View),DecorView里的dispatchTouchEvent方法如下. 这里的Callback的cb其实就是Activity的attach()方法里的设置回调。

看下PhoneWindow.DecorView dispatchTouchEvent method

# Android View的事件分发 分析源码_第4张图片
DecprdView_dispatchTouchEvent.jpg

回调cb就代表Activity,回调会在Activity的onAttach的时候进行设置.

# Android View的事件分发 分析源码_第5张图片
Activity_onAttach.jpg

再看cb执行dispatchTouchEvent method.即执行Activity的dispatchTouchEvent,之后Activity会把事件又重新传递到DecorView,然后会调用父类(ViewGroup)的dispatchTouchEvent 将事件传给父类处理。即调用ViewGroup 和 View的事件分发机制。

总算绕回到View ViewGroup的事件分发机制。


View 或者 ViewGroup的事件分发机制

事件的概念

在Android中,事件主要包括点按、长按、拖拽、滑动等,点按又包括单击和双击,另外还包括单指操作和多指操作。所有这些都构成了Android中的事件响应。

事件分为三种:

  • 按下(ACTION_DOWN)
  • 移动(ACTION_MOVE)
  • 抬起(ACTION_UP)

ViewGroup和View的分发

相关函数:

  • ViewGroup

    1. public boolean dispatchTouchEvent(MotionEvent event)
    2. public boolean onTouchEvent(MotionEvent event)
    3. public boolean onInterceptTouchEvent(MotionEvent event)
  • View

    1. public boolean dispatchTouchEvent(MotionEvent event)
    2. public boolean onTouchEvent(MotionEvent event)

ViewGroup和View的事件分发是向下传递的,即ViewGroup会一层层向子View分发事件,直到消费事件或者被丢弃。由此可以看出ViewGroup和View相关函数的返回类型都是Boolean,可以直到Boolean类型决定了某一事件是否是继续往下传,还是被拦截了,或是被消费了。

ViewGroup和View的相关函数都接受参数MotionEvent类型的参数,MotionEvent继承于InputEvent,用于标记各种动作事件。之前提到的ACTIONDOWN、ACTIONMOVE、ACTION_UP都是MotinEvent中定义的常量。我们通过MotionEvent传进来的事件类型来判断接收的是哪一种类型的事件。

ViewGroup继承View,即ViewGroup是一个特殊的View,ViewGroup在事件分发中比View多一个函数, onInterceptTouchEvent函数(拦截事件的函数),顾名思义,就是在ViewGroup一层就将事件拦截下来进行处理。

所以一共是三个函数,我们来总结下三个函数的功能:

  • dispatchTouchEvent方法用于事件的分发,Android中所有的事件都必须经过这个方法的分发,然后决定是自身消费当前事件还是继续往下分发给子控件处理。返回true表示不继续分发,事件没有被消费。返回false则继续往下分发,如果是ViewGroup则分发给onInterceptTouchEvent进行判断是否拦截该事件。

  • onTouchEvent方法用于事件的处理,返回true表示消费处理当前事件,返回false则不处理,交给子控件进行继续分发。

  • onInterceptTouchEvent是ViewGroup中才有的方法,View中没有,它的作用是负责事件的拦截,返回true的时候表示拦截当前事件,不继续往下分发,交给自身的onTouchEvent进行处理。返回false则不拦截,继续往下传。这是ViewGroup特有的方法,因为ViewGroup中可能还有子View,而在Android中View中是不能再包含子View的(iOS可以)。

流程简述:

1.ViewGroup执行dispatchTouchEvent进行分发事件,可以进行拦截或者向下分发给子View。如果拦截事件则执行自己的onTouchEvent。
2.子View接受到事件执行dispatchTouchEvent,在这之中如果设置了Listener监听器,则先执行onTouch方法,然后执行onTouchEvent方法。
然后事件被消费结束。

补充如果子View的Listener监听器重写的onTouch方法返回true,则不会继续执行onTouchEvent方法,如果返回false则表示没有消费结束,继续执行onTouchEvent方法。


总结

  • 底层将触摸事件传递到上层的Activity,Activity再传递到ViewGroup,ViewGroup拦截或者不拦截,不拦截则传递分发到子View进行消费,如果这个事件一直没被消费则自动被丢弃。

你可能感兴趣的:(# Android View的事件分发 分析源码)