Android O: 触摸事件传递流程源码分析(上)

本文深入分析Android O中触摸事件的传递流程,从Activity的dispatchTouchEvent开始,探讨如何分发到ViewGroup,以及ViewGroup如何处理 Accessibility Focus 事件,拦截事件和查找处理事件的子View。内容涵盖了事件的安全性检测、拦截机制和后续处理步骤。
摘要由CSDN通过智能技术生成

前面的博客中,我们通过例子分析了一下Android中事件传递的流程,
详细内容可以参考:Android触摸事件传递机制简要分析

贯穿整个Android的触摸事件分发的流程,基本可以抽象成以下的伪代码:

public boolean dispatchTouchEvent(MotionEvent ev){
    boolean handle = false;
    if(onInterceptTouchEvent(ev)){
        handle = onTouchEvent(ev);
    }else{
        handle = child.dispatchTouchEvent(ev);
    }
    return handle;
}

如果一个事件传递到了ViewGroup处,首先会判断当前ViewGroup是否要拦截事件,
即调用onInterceptTouchEvent()方法。

如果返回true,则表示ViewGroup拦截事件,
那么ViewGroup就会调用自身的onTouchEvent来处理事件;

如果返回false,表示ViewGroup不拦截事件,
此时事件会分发到它的子View处,即调用子View的dispatchTouchEvent方法。

如此反复直到事件被消耗掉。

本篇博客,我们以Android O的代码为例,看看对应流程的源码。
考虑到事件分发的流程较为繁琐,本篇博客主要针对Activity和ViewGroup部分。


一、Activity部分
系统有一个线程在循环收集屏幕硬件信息。
当用户触摸屏幕时,该线程会把从硬件设备收集到的信息,
封装成一个MotionEvent对象,然后把该对象存放到一个消息队列中。

与此对应,系统的另一个线程循环的读取消息队列中的MotionEvent,然后交给WMS去派发。
WMS把该事件派发给当前处于Active状态的Activity,即处于活动栈最顶端的Activity。

我们就从Activity的dispatchTouchEvent入手,看看整个事件分发的流程:

    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            //空实现,其用途注释已经说的比较清楚了
            //若需要了解用户点击界面,可以自行实现该接口
            //Implement this method if you wish to know that the user has
            //interacted with the device in some way while your activity is running.
            onUserInteraction();
        }

        //首先进行事件分发,事件被消费掉就会返回true
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }

        //如果事件没有没消费掉,那么就会调用Activity的onTouchEvent
        return onTouchEvent(ev);
    }

从上面的代码容易看出,Activity收到触摸事件后首先会进行分发;
如果事件在分发的过程中没被消费掉,最终会被Activity的onTouchEvent处理。

在继续分析之前,我们先看看Activity的getWindow函数:

    public Window getWindow() {
        //返回Activity持有的mWindow对象
        return mWindow;
    }

mWindow对象是Activity显示在界面上时创建的,如下所示:

    final void attach(.....) {
        ........
        //实际上是一个PhoneWindow对象
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        ........
    }

由上面的代码易知,Activity分发的事件实际上交给了PhoneWindow。
对应分发事件的函数如下:

    public boolean superDispatchTouchEvent(MotionEvent event) {
        //mDecor的类型为DecorView,在PhoneWindow初始化时得到
        return mDecor.superDispatchTouchEvent(event);
    }

DecorView继承FrameLayout,后者继承ViewGroup,
于是上述代码最终会将触摸事件递交给ViewGroup处理。

二、ViewGroup部分
接下来我们跟进ViewGroup的dispatchTouchEvent函数。

2.1 处理Accessibility Focus事件

public boolean dispatchTouchEvent(MotionEvent ev) {
    .......
    // If the event targets the accessibility focused view and this is it, start
    // normal event dispatch. Maybe a descendant is what will handle the click.
    if (ev.isTargetAccessibilityFocus() && isAccessibilityFocusedViewOrHost()) {
        ev.setTargetAccessibilityFocus(false);
    }
    .......

ViewGroup收到触摸事件后,首先需要处理特殊情况,
即携带FLAG_TARGET_ACCESSIBILITY_FOCUS的MotionEvent。
该标志位的含义可以参考注释:

/**
* 1、 Private flag indicating that this event was synthesized by the system and
*    should be delivered to the accessibility focused view first.
* 
* 2、 When being dispatched such an event is not handled by predecessors of the accessibility
* focused view and after the event reaches that view the fla
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值