返回

事件分发之旅:从源码窥探事件流

Android

事件分发机制(二):源码篇

序言

继上篇博文对事件分发的精妙解析之后,我们踏上了探寻事件分发机制源码之旅。通过亲身深入源码,我们将从微观视角揭开事件流的奥秘。

事件流的U型之旅

事件分发,正如我们之前所述,宛如一个U型流。事件从Activity顶端出发,向下逐级传递,直至触及底部View。如果途中任何View消费了事件,U型流便在此中断,事件止步于此。反之,事件将继续下行,最终由Activity的onTouchEvent()方法处理。

源码剖析

1. onTouchEvent()方法

Activity的onTouchEvent()方法是事件流的终点。若事件未被任何View消费,该方法便负责处理剩余事件。其代码如下:

public boolean onTouchEvent(MotionEvent event) {
    if (mDelegate != null) {
        mDelegate.onTouchEvent(event);
    } else {
        return super.onTouchEvent(event);
    }
}

如上所示,onTouchEvent()方法首先检查是否存在委托对象mDelegate。如果存在,则将事件委托给该对象处理;否则,调用父类方法处理。

2. dispatchTouchEvent()方法

dispatchTouchEvent()方法是事件流的核心。其负责将事件逐级向下传递给子View。其代码如下:

public boolean dispatchTouchEvent(MotionEvent event) {
    if (!mAdded) {
        return false;
    }

    boolean canConsume = onFilterTouchEventForSecurity(event);
    if (!canConsume) {
        return false;
    }

    // ...省略部分代码...

    if (mFrameStats != null) {
        mFrameStats.onTouchEvent();
    }

    int action = event.getAction();
    if (mDelegate != null) {
        mDelegate.onDispatchTouchEvent(event);
    }

    // ...省略部分代码...
}

dispatchTouchEvent()方法首先检查Activity是否已添加到Window中。如果不是,则直接返回false。接下来,它调用onFilterTouchEventForSecurity()方法,检查事件是否被安全过滤掉。如果是,则返回false。

之后,该方法执行以下操作:

  • 更新帧统计信息。
  • 获取事件动作类型。
  • 将事件委托给mDelegate对象处理。
  • 调用onInterceptTouchEvent()方法,检查事件是否被拦截。
  • 如果事件未被拦截,则调用onTouchEvent()方法,将事件传递给当前View。

3. onInterceptTouchEvent()方法

onInterceptTouchEvent()方法由ViewGroup类实现,它决定是否拦截子View的触摸事件。其代码如下:

public boolean onInterceptTouchEvent(MotionEvent ev) {
    if (mInputEventConsistencyVerifier != null) {
        mInputEventConsistencyVerifier.onTouchEvent(ev, this);
    }

    int action = ev.getAction();
    boolean intercepted = false;

    // ...省略部分代码...

    return intercepted;
}

onInterceptTouchEvent()方法首先调用InputEventConsistencyVerifier,用于检查触摸事件的合法性。然后,它获取事件动作类型并设置一个intercepted标志,表示事件是否被拦截。

接下来,该方法执行以下操作:

  • 调用子View的onInterceptTouchEvent()方法,询问子View是否拦截事件。
  • 根据子View的返回结果,更新intercepted标志。
  • 返回intercepted标志,表示事件是否被拦截。

结论

通过对源码的深入剖析,我们更加清晰地理解了事件分发机制的运作原理。事件流如同一个U型流,从Activity逐级向下传递,直至最终被消费或处理。源码中的关键方法,如dispatchTouchEvent()和onInterceptTouchEvent(),扮演着至关重要的角色,控制着事件的流动。

本次源码之旅,不仅让我们深入技术细节,更让我们领略了Android底层框架的精妙设计。在未来的技术探索中,源码分析将始终作为我们获取真知灼见的宝贵途径。