美文网首页Android开发Android知识Android开发经验谈
# Android View的事件分发 分析源码

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

作者: 伍零一 | 来源:发表于2016-05-08 09:09 被阅读276次

    引言

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

    分两部分来说:

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

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

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

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

    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

    ViewRoot_handleMessage.jpg

    看下ViewRoot.deliverPointerEvent method

    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

    DecprdView_dispatchTouchEvent.jpg

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

    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的事件分发 分析源码

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