Android13 Input -view 事件分发

208 阅读24分钟

View事件分发

InputDispatcher通过与对应窗口建立连接通道,将事件信息封装成InputMessgae,通过InputChannel将信息发送到窗口端socket,looper监听到fd有数据写入,执行NativeInputEventReceiver::handleEvent函数,读取窗口socket端数据,在返回到java端进行处理

InputEventReceiver.java
    private void dispatchInputEvent(int seq, InputEvent event) {
        mSeqMap.put(event.getSequenceNumber(), seq);
        onInputEvent(event);
    }

执行InputEventReceiver的重写函数onInputEvent
在ViewRootImpl中定义了InputEventReceiver的子类WindowInputEventReceiver

ViewRootImpl.java
final class WindowInputEventReceiver extends InputEventReceiver {
        public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
            super(inputChannel, looper);
        }

        @Override
        public void onInputEvent(InputEvent event) {
            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventForCompatibility");
            List<InputEvent> processedEvents;
            try {
                processedEvents =
                    mInputCompatProcessor.processInputEventForCompatibility(event);
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            }
            if (processedEvents != null) {
                if (processedEvents.isEmpty()) {
                    // InputEvent consumed by mInputCompatProcessor
                    finishInputEvent(event, true);
                } else {
                    for (int i = 0; i < processedEvents.size(); i++) {
                        enqueueInputEvent(
                                processedEvents.get(i), this,
                                QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY, true);
                    }
                }
            } else {
                enqueueInputEvent(event, this, 0, true);
            }
        }

  1. 创建processedEvents集合
  2. processInputEventForCompatibility考虑在发送app前做适配
  3. 判断适配处理后的事件是否存在
  • 不存在代表事件处理完毕 将事件反馈给到InputDispatcher
  • 存在 遍历processedEvents执行enqueueInputEvent入队派发
  1. 适配处理后的事件不存在 代表当前事件不需要适配,直接执行enqueueInputEvent入队派发
ViewRootImpl.java
   void enqueueInputEvent(InputEvent event,
            InputEventReceiver receiver, int flags, boolean processImmediately) {
        QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);

        if (event instanceof MotionEvent) {
            MotionEvent me = (MotionEvent) event;
            if (me.getAction() == MotionEvent.ACTION_CANCEL) {
                EventLog.writeEvent(EventLogTags.VIEW_ENQUEUE_INPUT_EVENT, "Motion - Cancel",
                        getTitle().toString());
            }
        } else if (event instanceof KeyEvent) {
            KeyEvent ke = (KeyEvent) event;
            if (ke.isCanceled()) {
                EventLog.writeEvent(EventLogTags.VIEW_ENQUEUE_INPUT_EVENT, "Key - Cancel",
                        getTitle().toString());
            }
        }
        // Always enqueue the input event in order, regardless of its time stamp.
        // We do this because the application or the IME may inject key events
        // in response to touch events and we want to ensure that the injected keys
        // are processed in the order they were received and we cannot trust that
        // the time stamp of injected events are monotonic.
        QueuedInputEvent last = mPendingInputEventTail;
        if (last == null) {
            mPendingInputEventHead = q;
            mPendingInputEventTail = q;
        } else {
            last.mNext = q;
            mPendingInputEventTail = q;
        }
        mPendingInputEventCount += 1;
        Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
                mPendingInputEventCount);

        if (processImmediately) {
            doProcessInputEvents();
        } else {
            scheduleProcessInputEvents();
        }
    }

  1. 将event receiver flag 封装为QueuedInputEvent
  2. 判断event能否转为MotionEvent
  3. 判断MotionEvent.action是MotionEvent.ACTION_CANCEL
    EventLog写入cancel事件
  4. 判断KeyEvent.action是KeyEvent.isCanceled
    EventLog写入cancel事件
  5. input事件队列追加事件
  6. 这里processImmediately为true 执行doProcessInputEvents
ViewRootImpl.java
    void doProcessInputEvents() {
        // Deliver all pending input events in the queue.
        while (mPendingInputEventHead != null) {
            QueuedInputEvent q = mPendingInputEventHead;
            mPendingInputEventHead = q.mNext;
            if (mPendingInputEventHead == null) {
                mPendingInputEventTail = null;
            }
            q.mNext = null;

            mPendingInputEventCount -= 1;
            Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
                    mPendingInputEventCount);

            mViewFrameInfo.setInputEvent(mInputEventAssigner.processEvent(q.mEvent));

            deliverInputEvent(q);
        }

        // We are done processing all input events that we can process right now
        // so we can clear the pending flag immediately.
        if (mProcessInputEventsScheduled) {
            mProcessInputEventsScheduled = false;
            mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
        }
    }

  1. 从缓存事件队列头部取出事件
  2. 缓存事件数量-1
  3. deliverInputEvent 分发事件
ViewRootImpl.java
    private void deliverInputEvent(QueuedInputEvent q) {
        Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
                q.mEvent.getId());

        if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent src=0x"
                    + Integer.toHexString(q.mEvent.getSource()) + " eventTimeNano="
                    + q.mEvent.getEventTimeNano() + " id=0x"
                    + Integer.toHexString(q.mEvent.getId()));
        }
        try {
            if (mInputEventConsistencyVerifier != null) {
                Trace.traceBegin(Trace.TRACE_TAG_VIEW, "verifyEventConsistency");
                try {
                    mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
                } finally {
                    Trace.traceEnd(Trace.TRACE_TAG_VIEW);
                }
            }

            InputStage stage;
            if (q.shouldSendToSynthesizer()) {
                stage = mSyntheticInputStage;
            } else {
                stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
            }

            if (q.mEvent instanceof KeyEvent) {
                Trace.traceBegin(Trace.TRACE_TAG_VIEW, "preDispatchToUnhandledKeyManager");
                try {
                    mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);
                } finally {
                    Trace.traceEnd(Trace.TRACE_TAG_VIEW);
                }
            }

            if (stage != null) {
                handleWindowFocusChanged();
                stage.deliver(q);
            } else {
                finishInputEvent(q);
            }
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
    }

  1. 验证输入事件的一致性。如果事件存在异常,则会抛出异常并终止程序的执行
  2. 输入事件的处理流程包括多个 Stage,每个 Stage 负责一些特定的任务,shouldSendToSynthesizer用于处理,mSyntheticInputStage主要负责处理需要进行输入法合成的输入事件
  3. q.shouldSendToSynthesizer() false 代表不是合成的输入事件,根据shouldSkipIme确认选择mFirstPostImeInputStage 处理输入法事件还是mFirstInputStage处理输入事件的第一阶段
  4. 判断mEvent的类型是否为KeyEvent,是的话执行 mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);
  5. 上述选择的stage不为空,检查窗口焦点是否发生变化来调整事件的派发,之后调用Stage.deliver来派发
    在研究Stage.deliver派发事件前要先了解stage的概念
ViewRootImpl.java
 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
            int userId) {
                CharSequence counterSuffix = attrs.getTitle();
                mSyntheticInputStage = new SyntheticInputStage();
                InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
                InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
                        "aq:native-post-ime:" + counterSuffix);
                InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
                InputStage imeStage = new ImeInputStage(earlyPostImeStage,
                        "aq:ime:" + counterSuffix);
                InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
                InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
                        "aq:native-pre-ime:" + counterSuffix);

                mFirstInputStage = nativePreImeStage;
                mFirstPostImeInputStage = earlyPostImeStage;
                mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;

}

  1. 可以看到在执行setView方法
  2. 构建了7个阶段
    AsyncInputStage:这个阶段是输入系统的异步处理阶段。在用户输入事件发生后,首先会经过硬件驱动层的处理,然后传递给应用程序的主线程。在主线程中,输入事件会被封装并发送到 AsyncInputStage 进行异步处理。这个阶段的任务包括事件的解析、转换、分发等操作,确保输入事件能够被正确地传递给相应的目标视图进行处理。
    第一阶段:
    SyntheticInputStage 是 Android 系统中的一个输入阶段,它属于系统输入处理的一部分。具体来说,SyntheticInputStage 用于处理合成输入事件。

在 Android 中,合成输入事件是由系统模拟生成的输入事件,而不是由用户实际触发的。合成输入事件可以用于模拟用户操作,例如自动化测试、辅助功能等场景。SyntheticInputStage 负责接收和处理这些合成输入事件,并将它们传递给目标视图进行相应的处理。

在 SyntheticInputStage 阶段,系统会将合成输入事件按照特定的顺序进行处理,通常包括以下几个步骤:

合成输入事件的生成:系统根据需要生成合成输入事件,这些事件可以模拟用户的点击、滑动、长按等操作。生成合成输入事件的方式可以通过调用相应的 API 或使用相关的工具类来实现。

合成输入事件的分发:生成的合成输入事件会被系统分发到相应的 SyntheticInputStage 阶段进行处理。系统会按照一定的规则确定目标视图,然后将合成输入事件传递给目标视图进行处理。

合成输入事件的处理:SyntheticInputStage 接收到合成输入事件后,会将事件传递给目标视图进行处理。目标视图可以是应用程序中的任何视图,例如按钮、文本框等。目标视图根据接收到的合成输入事件来执行相应的操作,如执行点击操作、滚动操作等。

需要注意的是,SyntheticInputStage 阶段是系统的一部分,一般情况下开发者无需直接操作或干预该阶段的过程。这个阶段在 Android 系统内部进行,主要目的是处理合成输入事件,以模拟用户操作或实现辅助功能。
第二阶段:
ViewPostImeInputStage 是 Android 系统中的一个输入阶段,它属于系统输入处理的一部分。具体来说,ViewPostImeInputStage 用于处理 IME(输入法)相关的输入事件。

在 Android 中,IME 输入事件是由输入法软件发送给应用程序的。当用户在文本框或其他可编辑视图中进行输入时,输入法软件会生成相应的输入事件,并将其发送到应用程序中。ViewPostImeInputStage 阶段负责接收和处理这些输入事件,并将它们传递给目标视图进行相应的处理。

在 ViewPostImeInputStage 阶段,系统会按照以下步骤处理 IME 相关的输入事件:

IME 输入事件的生成:当用户在输入法软件中输入文字时,输入法软件会生成相应的输入事件,如文本变化事件、光标位置变化事件等。

IME 输入事件的分发:输入法软件将生成的输入事件发送到当前活动的应用程序中。系统会将这些输入事件分发给适当的 ViewPostImeInputStage 阶段进行处理。

IME 输入事件的处理:ViewPostImeInputStage 接收到 IME 输入事件后,会将事件传递给目标视图进行处理。目标视图通常是当前正在与用户交互的文本框或可编辑视图。目标视图根据接收到的输入事件来更新文本内容、光标位置等,并可能触发相应的监听器或回调方法。

需要注意的是,ViewPostImeInputStage 阶段是系统的一部分,开发者无需直接操作或干预该阶段的过程。这个阶段在 Android 系统内部进行,主要目的是处理与输入法相关的输入事件,以确保用户的输入能够正确地显示和处理。
第三阶段:
nativePostImeStage是在提到原生(native)层面的输入处理,可以理解为与输入法相关的底层操作和事件。

在底层的原生开发中,涉及到输入法的处理通常包括以下几个方面:

输入法管理器(InputMethodManager):在原生开发中,可以使用输入法管理器来控制输入法的显示、隐藏以及切换。通过输入法管理器,可以获取当前的输入法信息、打开或关闭输入法窗口、获取输入法视图等。

输入法事件处理:原生开发可以处理与输入法相关的事件,例如键盘按键事件(KeyEvent)、触摸事件(MotionEvent)等。通过监听和处理这些事件,可以实现与输入法交互的功能,如捕获按键输入、响应触摸操作等。

输入框处理:原生开发还可以针对输入框进行处理,包括输入框的创建、位置和大小的调整、内容的显示和编辑等。通过与输入框的交互,可以实现与用户的输入交互和数据处理。
第四阶段:

接下来我们看其中一个stage的构造函数

    final class ViewPostImeInputStage extends InputStage {
        public ViewPostImeInputStage(InputStage next) {
            super(next);
        }

这里可以看到将ViewPostImeInputStage关联的下一阶段stage,放到父类InputStage的构造函数中

        public InputStage(InputStage next) {
            mNext = next;
        }

这里看到下个阶段的stage赋值到mNext中
那么在执行父类InputStage的方法时比如

        protected void onDeliverToNext(QueuedInputEvent q) {
            if (DEBUG_INPUT_STAGES) {
                Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q);
            }
            if (mNext != null) {
                mNext.deliver(q);
            } else {
                finishInputEvent(q);
            }
        }

这里调用 mNext.deliver(q)就来到了下个阶段的deliver函数中

        public final void deliver(QueuedInputEvent q) {
            if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
                forward(q);
            } else if (shouldDropInputEvent(q)) {
                finish(q, false);
            } else {
                traceEvent(q, Trace.TRACE_TAG_VIEW);
                final int result;
                try {
                    result = onProcess(q);
                } finally {
                    Trace.traceEnd(Trace.TRACE_TAG_VIEW);
                }
                apply(q, result);
            }
        }

在这里执行下一个阶段的onProcess函数,将处理结果和事件给到
apply(q, result)

        protected void apply(QueuedInputEvent q, int result) {
            if (result == FORWARD) {
                forward(q);
            } else if (result == FINISH_HANDLED) {
                finish(q, true);
            } else if (result == FINISH_NOT_HANDLED) {
                finish(q, false);
            } else {
                throw new IllegalArgumentException("Invalid result: " + result);
            }
        }

这里根据处理结果执行不同函数 关于apply来说由于stage不同分为了同步异步俩个部分 这里主要看同步

        protected void forward(QueuedInputEvent q) {
            onDeliverToNext(q);
        }

执行onDeliverToNext方法

        protected void onDeliverToNext(QueuedInputEvent q) {
            if (DEBUG_INPUT_STAGES) {
                Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q);
            }
            if (mNext != null) {
                mNext.deliver(q);
            } else {
                finishInputEvent(q);
            }
        }

这里可以看到要分发到下下个阶段了,同时如果所有阶段都执行完就执行finishInputEvent给InputDispatcher反馈了
再看下finish函数

        protected void finish(QueuedInputEvent q, boolean handled) {
            q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
            if (handled) {
                q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
            }
            forward(q);
        }

handled为true代表事件处理完成事件加上QueuedInputEvent.FLAG_FINISHED_HANDLED flag ,分发下个阶段,下个阶段一看事件已经处理完了,那直接跳过平台来给InputDispatcher反馈

经过AsyncInputStage ViewPostImeInputStage阶段

    final class ViewPostImeInputStage extends InputStage {
        public ViewPostImeInputStage(InputStage next) {
            super(next);
        }

        @Override
        protected int onProcess(QueuedInputEvent q) {
            if (q.mEvent instanceof KeyEvent) {
                return processKeyEvent(q);
            } else {
                final int source = q.mEvent.getSource();
                if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
                    return processPointerEvent(q);
                } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
                    return processTrackballEvent(q);
                } else {
                    return processGenericMotionEvent(q);
                }
            }
        }

  1. 当前是KeyEvent执行processKeyEvent
  2. source是InputDevice.SOURCE_CLASS_POINTER 执行processPointerEvent
  3. source是InputDevice.SOURCE_CLASS_TRACKBALL执行processTrackballEvent事件
  4. 其他执行processGenericMotionEvent
        private int processPointerEvent(QueuedInputEvent q) {
            final MotionEvent event = (MotionEvent)q.mEvent;
            mHandwritingInitiator.onTouchEvent(event);

            mAttachInfo.mUnbufferedDispatchRequested = false;
            mAttachInfo.mHandlingPointerEvent = true;
            boolean handled = mView.dispatchPointerEvent(event);
            maybeUpdatePointerIcon(event);
            maybeUpdateTooltip(event);
            mAttachInfo.mHandlingPointerEvent = false;
            if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
                mUnbufferedInputDispatch = true;
                if (mConsumeBatchedInputScheduled) {
                    scheduleConsumeBatchedInputImmediately();
                }
            }
            return handled ? FINISH_HANDLED : FORWARD;
        }

  1. 获取event事件
  2. 执行 mView.dispatchPointerEvent(event)
  3. 根据结果确认当前是FINISH_HANDLED还是FORWARD
View.java
    public final boolean dispatchPointerEvent(MotionEvent event) {
        if (event.isTouchEvent()) {
            return dispatchTouchEvent(event);
        } else {
            return dispatchGenericMotionEvent(event);
        }
    }

1 检查事件是否为touch事件 是的话执行DecorView.dispatchTouchEvent

DecorView.java
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        final Window.Callback cb = mWindow.getCallback();
        return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
                ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
    }

  1. 获取phoneWindow的callback对象即窗口的Activity
  2. 执行Activity的dispatchTouchEvent方法
    关于为什么phoneWindow的callback对象即窗口的Activity
Activity.java
final void attach(......){
    ......
    mWindow = new PhoneWindow(this, window, activityConfigCallback);
    mWindow.setWindowControllerCallback(this);
    mWindow.setCallback(this); // 这里的 this 就是 Activity
    ......
}

接下来执行Activity的dispatchTouchEvent方法

Activity.java
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            onUserInteraction();
        }
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        return onTouchEvent(ev);
    }

  1. 首先ACTION_DOWN事件执行onUserInteraction这个空方法,通知用户,Activity已经接收到事件了
  2. 当前Activity的窗口执行superDispatchTouchEvent方法,派发成功返回true
  3. 如果上述都失败了,就执行Activity的onTouchEvent方法

接下来看当前Activity的窗口执行superDispatchTouchEvent方法

    @Override
    public boolean superDispatchTouchEvent(MotionEvent event) {
        return mDecor.superDispatchTouchEvent(event);
    }

  1. 执行DecorView的superDispatchTouchEvent方法

接下来看DecorView的superDispatchTouchEvent方法

    public boolean superDispatchTouchEvent(MotionEvent event) {
        return super.dispatchTouchEvent(event);
    }

  1. 执行父类的superDispatchTouchEvent方法,这里的super是ViewGroup

为什么这里的super是ViewGroup

public class DecorView extends FrameLayout

public class FrameLayout extends ViewGroup

  1. 可以看到最终的父类是ViewGroup
    在查看ViewGroup的dispatchTouchEvent方法前,先做一个java端事件派发总结:
    可以看到在输入事件通过NativeInputEventReciver的InputConsumer从InputChannel中读出由JNI ->java端 ->ViewRootImpl -> InputStage -> DecorView -> Activity -> PhoneWindow -> DecorView -> ViewGroup

接下来看ViewGroup的dispatchTouchEvent方法

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

        // 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);
        }

        boolean handled = false;
        // 判断此次触摸事件是否被过滤掉,条件由两个 flag 决定,FILTER_TOUCHES_WHEN_OBSCURED
        // 和 MotionEvent.FLAG_WINDOW_IS_OBSCURED,这两个 flag 用来表示
        // 当前接收触摸事件的 View 是否被遮挡或者隐藏,只有未被遮挡或隐藏才能
        // 进一步处理事件

        //事件安全检查
        if (onFilterTouchEventForSecurity(ev)) {
            final int action = ev.getAction();
            final int actionMasked = action & MotionEvent.ACTION_MASK;

            // Handle an initial down.
            //事件action为MotionEvent.ACTION_DOWN代表一次新的事件序列到来,需要清空上一次
            //事件序列的相关状态
            if (actionMasked == MotionEvent.ACTION_DOWN) {
                // Throw away all previous state when starting a new touch gesture.
                // The framework may have dropped the up or cancel event for the previous gesture
                // due to an app switch, ANR, or some other state change.
                cancelAndClearTouchTargets(ev);
                resetTouchState();
            }

            // Check for interception.
            final boolean intercepted;
            if (actionMasked == MotionEvent.ACTION_DOWN
                    || mFirstTouchTarget != null) {
                //Action为ACTION_DOWN或者mFirstTouchTarget(接收事件的目标)不为空
                final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
                //检查mGroupFlags是否为FLAG_DISALLOW_INTERCEPT
                //FLAG_DISALLOW_INTERCEPT这个为不允许拦截事件Flag
                if (!disallowIntercept) {
                    //父view调用onInterceptTouchEvent拦截事件
                    intercepted = onInterceptTouchEvent(ev);
                    ev.setAction(action); // restore action in case it was changed
                } else {
                    //设置intercepted(父View拦截Flag为false)
                    intercepted = false;
                }
            } else {
                // There are no touch targets and this action is not an initial down
                // so this view group continues to intercept touches.
                //当前Action不是ACTION_DOWN或者没有mFirstTouchTarget(接收事件的目标)
                //事件要被拦截
                intercepted = true;
            }
            // Check for cancelation.
            //resetCancelNextUpFlag(this)为true或者Action为ACTION_CANCEL
            //会设置canceled为true
            //resetCancelNextUpFlag方法指的View是否存在PFLAG_CANCEL_NEXT_UP_EVENT标志
            final boolean canceled = resetCancelNextUpFlag(this)
                    || actionMasked == MotionEvent.ACTION_CANCEL;

            // Update list of touch targets for pointer down, if needed.
            //是否为鼠标事件
            final boolean isMouseEvent = ev.getSource() == InputDevice.SOURCE_MOUSE;
            //mGroupFlags是否包含FLAG_SPLIT_MOTION_EVENTS并且不是鼠标事件
            //检查View是否支持事件拆分
            final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0
                    && !isMouseEvent;
            //定义新的接收事件的目标
            TouchTarget newTouchTarget = null;
            //事件是否派发到新的接收事件的目标的标志位
            boolean alreadyDispatchedToNewTouchTarget = false;
                if (!canceled && !intercepted) {
                //进入该判断的事件 未被取消并且拦截

                View childWithAccessibilityFocus = ev.isTargetAccessibilityFocus()
                        ? findChildWithAccessibilityFocus() : null;

                if (actionMasked == MotionEvent.ACTION_DOWN
                        || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
                        || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
                    //新事件序列开始的行为则进入该判断 
                    //获取事件Index
                    final int actionIndex = ev.getActionIndex(); // always 0 for down
                    //根据是否支持事件拆分获取触控点位
                    final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)
                            : TouchTarget.ALL_POINTER_IDS;

                    // Clean up earlier touch targets for this pointer id in case they
                    // have become out of sync.
                    //移除上次事件序列的触控点位
                    removePointersFromTouchTargets(idBitsToAssign);
                    //获取子视图数量
                    final int childrenCount = mChildrenCount;
                    //新的接收事件目标为空并且子视图不为0
                    if (newTouchTarget == null && childrenCount != 0) {
                        //获取x
                        final float x =
                                isMouseEvent ? ev.getXCursorPosition() : ev.getX(actionIndex);
                        //获取y
                        final float y =
                                isMouseEvent ? ev.getYCursorPosition() : ev.getY(actionIndex);
                        // Find a child that can receive the event.
                        // Scan children from front to back.
                        //获取预排续(按照Zorder顺序)子view集合
                        final ArrayList<View> preorderedList = buildTouchDispatchChildList();
                        //是否满足子view集合自定义排序
                        final boolean customOrder = preorderedList == null
                                && isChildrenDrawingOrderEnabled();
                        //子view数组
                        final View[] children = mChildren;
                        //根据zOrder由高到底遍历预排续view数组
                        for (int i = childrenCount - 1; i >= 0; i--) {
                            //获取子view的index
                            final int childIndex = getAndVerifyPreorderedIndex(
                                    childrenCount, i, customOrder);
                            //获取子view对象
                            final View child = getAndVerifyPreorderedView(
                                    preorderedList, children, childIndex);

                            // If there is a view that has accessibility focus we want it
                            // to get the event first and if not handled we will perform a
                            // normal dispatch. We may do a double iteration but this is
                            // safer given the timeframe.
                            if (childWithAccessibilityFocus != null) {
                                if (childWithAccessibilityFocus != child) {
                                    continue;
                                }
                                childWithAccessibilityFocus = null;
                                i = childrenCount;
                            }
                            //子视图是否可以接收事件或者当前事件的坐标是否在子视图中
                            if (!child.canReceivePointerEvents()
                                    || !isTransformedTouchPointInView(x, y, child, null)) {
                                //不满足条件则开启下一个View的遍历循环
                                ev.setTargetAccessibilityFocus(false);
                                continue;
                            }
                            //如果找到了事件所在的子视图
                            //getTouchTarget会根据子视图获取的newTouchTarget
                            //newTouchTarget不为空代表子视图之前处理过事件(多指触碰)
                            //对于单指down行为 newTouchTarget一定为null
                            newTouchTarget = getTouchTarget(child);
                            if (newTouchTarget != null) {
                                // Child is already receiving touch within its bounds.
                                // Give it the new pointer in addition to the ones it is handling.
                                //更新接收事件目标中触控位的值
                                newTouchTarget.pointerIdBits |= idBitsToAssign;
                                //跳出循环 当前已找到对应处理该事件的view
                                break;
                            }
                            //如果有设置 PFLAG_CANCEL_NEXT_UP_EVENT,在此清除
                            resetCancelNextUpFlag(child);
                            //dispatchTransformedTouchEvent方法为事件找到真正处理它的子控件View
                            if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
                                // Child wants to receive touch within its bounds.
                                //事件派发成功找到子控件View
                                //记录最后一次down时间
                                mLastTouchDownTime = ev.getDownTime();
                                //存在预排序view集合
                                if (preorderedList != null) {
                                    // childIndex points into presorted list, find original index
                                    for (int j = 0; j < childrenCount; j++) {
                                        //遍历预排续View数组获取处理该事件的View的childIndex
                                        if (children[childIndex] == mChildren[j]) {
                                            mLastTouchDownIndex = j;
                                            break;
                                        }
                                    }
                                } else {
                                    //最后一次down事件index是原始子视图的index
                                    mLastTouchDownIndex = childIndex;
                                }
                                //获取最后一次down事件的 x y坐标
                                mLastTouchDownX = ev.getX();
                                mLastTouchDownY = ev.getY();
                                //根据子视图和触控点创建newTouchTarget
                                newTouchTarget = addTouchTarget(child, idBitsToAssign);
                                //flag设置为true
                                alreadyDispatchedToNewTouchTarget = true;
                                break;
                            }

                            // The accessibility focus didn't handle the event, so clear
                            // the flag and do a normal dispatch to all children.
                            ev.setTargetAccessibilityFocus(false);
                        }
                        //清空预排序view集合
                        if (preorderedList != null) preorderedList.clear();
                    }
                    //如果没找到事件所对应的子view
                    if (newTouchTarget == null && mFirstTouchTarget != null) {
                        // Did not find a child to receive the event.
                        // Assign the pointer to the least recently added target.
                        newTouchTarget = mFirstTouchTarget;
                        while (newTouchTarget.next != null) {
                            newTouchTarget = newTouchTarget.next;
                        }
                        //将最近一次处理事件的TouchTarget更新为处理该事件的TouchTarget
                        newTouchTarget.pointerIdBits |= idBitsToAssign;
                    }
                }
            }
            // Dispatch to touch targets.
            if (mFirstTouchTarget == null) {
                // No touch targets so treat this as an ordinary view.
                //如果没有触摸目标,则将触摸事件视为普通的视图
                handled = dispatchTransformedTouchEvent(ev, canceled, null,
                        TouchTarget.ALL_POINTER_IDS);
            } else {
                // Dispatch to touch targets, excluding the new touch target if we already
                // dispatched to it.  Cancel touch targets if necessary.
                TouchTarget predecessor = null;
                TouchTarget target = mFirstTouchTarget;
                //遍历TouchTarget集合
                while (target != null) {
                    //保存下一个TouchTarget到next
                    final TouchTarget next = target.next;
                    if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
                        //如果已经将事件派发到新的TouchTarget
                        handled = true;
                    } else {
                        //检查View是否包含PFLAG_CANCEL_NEXT_UP_EVENT这个flag
                        final boolean cancelChild = resetCancelNextUpFlag(target.child)
                                || intercepted;
                        //将事件派发到目标视图中,这里一般是处理Move事件
                        if (dispatchTransformedTouchEvent(ev, cancelChild,
                                target.child, target.pointerIdBits)) {
                            //处理成功
                            handled = true;
                        }
                        //如果需要去掉子视图,也需要调整链表的中该视图对于的touchTarget
                        if (cancelChild) {
                            if (predecessor == null) {
                                mFirstTouchTarget = next;
                            } else {
                                predecessor.next = next;
                            }
                            target.recycle();
                            target = next;
                            continue;
                        }
                    }
                    predecessor = target;
                    target = next;
                }
            }

            // Update list of touch targets for pointer up or cancel, if needed.
            if (canceled
                    || actionMasked == MotionEvent.ACTION_UP
                    || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
                //处理up事件,清空touchTarget链表
                resetTouchState();
            } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
                //可拆分并且存在多指抬起
                //根据actionIndex获取触控点idBitsToRemove然后调整touchTarget的触控点
                final int actionIndex = ev.getActionIndex();
                final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
                removePointersFromTouchTargets(idBitsToRemove);
            }
        }

总结:

  1. 关于ViewGroup的事件派发,首先onFilterTouchEventForSecurity方法检查接收事件的View是否被遮挡,遮挡的话是要cancel的,
  2. 对于一次down行为,可以理解为一次新的事件序列,要清空TouchTarget链表。
  3. 对于一次down行为,一定会被ViewGroup拦截进行onInterceptTouchEvent方法检查是否拦截成功,对于单指操作来说一旦down事件被拦截 该次事件序列的MOVE UP都会被拦截但不在执行onInterceptTouchEvent方法,子 View 可以通过 requestDisallowInterceptTouchEvent 方法请求父 View 不要拦截
    同样关于onInterceptTouchEvent方法方法也不一定会拦截掉down事件,也要做条件判断,后续细看
  4. 检查事件是否被cancel
  5. 检查事件资源是否为鼠标事件
  6. 检查事件是否可拆分
  7. 定义事件派发标志位
  8. 在事件不被cancel和intercept时,单指Down行为,多指可拆分的Pointer_Down行为,以及鼠标悬浮MOVE行为,这种新事件序列行为
    以单指Down行为来说
    首先获取 x,y坐标
    获取Zorder预排续的View集合
    遍历View集合 检查View是否可以接收事件,事件坐标是否在View内
    不满足 轮询下一个View
    满足 执行dispatchTransformedTouchEvent方法 派发给子View处理该事件
    处理成功,构建newTouchTarget来保存View,后续事件序列的事件可以直接派发到该View
    如果没找到子View处理该事件,android的机制是让最近一次的TouchTarget来处理该事件
    接下来单指Move行为
    就执行下述mFirstTouchTarget链表遍历,找到合适的子View处理行为事件
    接下来单指Up行为
    执行resetTouchState()方法 清空链表

接下来看一下cancelAndClearTouchTargets方法

    private void cancelAndClearTouchTargets(MotionEvent event) {
        if (mFirstTouchTarget != null) {
            boolean syntheticEvent = false;
            if (event == null) {
                final long now = SystemClock.uptimeMillis();
                event = MotionEvent.obtain(now, now,
                        MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
                event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
                syntheticEvent = true;
            }

            for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
                resetCancelNextUpFlag(target.child);
                dispatchTransformedTouchEvent(event, true, target.child, target.pointerIdBits);
            }
            clearTouchTargets();

            if (syntheticEvent) {
                event.recycle();
            }
        }
    }

1 检查mFirstTouchTarget是否为空
2 如果事件为空 根据当前时间生成Cancel事件,设置syntheticEvent为true
3 遍历mFirstTouchTarget链表,执行resetCancelNextUpFlag方法,向上次事件序列的子View发送cancel事件
4 清空touchTarget链表

接下来先看resetCancelNextUpFlag方法

private static boolean resetCancelNextUpFlag(@NonNull View view) {
        if ((view.mPrivateFlags & PFLAG_CANCEL_NEXT_UP_EVENT) != 0) {
            view.mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
            return true;
        }
        return false;
    }

去掉视图的 PFLAG_CANCEL_NEXT_UP_EVENT flag

接下来看dispatchTransformedTouchEvent方法

    private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
            View child, int desiredPointerIdBits) {
        final boolean handled;

        // Canceling motions is a special case.  We don't need to perform any transformations
        // or filtering.  The important part is the action, not the contents.
        final int oldAction = event.getAction();
        if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
            event.setAction(MotionEvent.ACTION_CANCEL);
            if (child == null) {
                handled = super.dispatchTouchEvent(event);
            } else {
                handled = child.dispatchTouchEvent(event);
            }
            event.setAction(oldAction);
            return handled;
        }

      
    }

因为 上述中cancel为true会向View发送cancel事件取消上次事件序列

接下来看下clearTouchTargets方法

    private void clearTouchTargets() {
        TouchTarget target = mFirstTouchTarget;
        if (target != null) {
            do {
                TouchTarget next = target.next;
                target.recycle();
                target = next;
            } while (target != null);
            mFirstTouchTarget = null;
        }
    }

清空mFirstTouchTarget 触控目标列表 将触控目标的view设置为null。

接下来看

    private void resetTouchState() {
        //清空touchTarget
        clearTouchTargets();
        //如果View的PFLAG_CANCEL_NEXT_UP_EVENT存在则去除
        resetCancelNextUpFlag(this);
        //去除FLAG_DISALLOW_INTERCEPT flag
        mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
        mNestedScrollAxes = SCROLL_AXIS_NONE;
    }

接下来看下onInterceptTouchEvent方法

    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (ev.isFromSource(InputDevice.SOURCE_MOUSE)
                && ev.getAction() == MotionEvent.ACTION_DOWN
                && ev.isButtonPressed(MotionEvent.BUTTON_PRIMARY)
                && isOnScrollbarThumb(ev.getX(), ev.getY())) {
            return true;
        }
        return false;
    }

可以看到事件满足下述条件才会返回true或者
或者actionMasked != MotionEvent.ACTION_DOWN才会设置 ,如果onInterceptTouchEvent失败 intercepted = false。

接下来看下removePointersFromTouchTargets方法

    private void removePointersFromTouchTargets(int pointerIdBits) {
        TouchTarget predecessor = null;
        TouchTarget target = mFirstTouchTarget;
        while (target != null) {
            final TouchTarget next = target.next;
            if ((target.pointerIdBits & pointerIdBits) != 0) {
                target.pointerIdBits &= ~pointerIdBits;
                if (target.pointerIdBits == 0) {
                    if (predecessor == null) {
                        mFirstTouchTarget = next;
                    } else {
                        predecessor.next = next;
                    }
                    target.recycle();
                    target = next;
                    continue;
                }
            }
            predecessor = target;
            target = next;
        }
    }

这里遍历TouchTarget链表的pointerIdBits与新事件的idBitsToAssign进行比较,来清除TouchTarget链表的之前TouchTarget的pointerIdBits

接下来看下dispatchTransformedTouchEvent方法

    private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
            View child, int desiredPointerIdBits) {
        final boolean handled;

        // Canceling motions is a special case.  We don't need to perform any transformations
        // or filtering.  The important part is the action, not the contents.
        //获取事件Action
        final int oldAction = event.getAction();
        //如果存在cancel 则向View派发cancel事件
        if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
            event.setAction(MotionEvent.ACTION_CANCEL);
            if (child == null) {
                handled = super.dispatchTouchEvent(event);
            } else {
                handled = child.dispatchTouchEvent(event);
            }
            event.setAction(oldAction);
            return handled;
        }

        // Calculate the number of pointers to deliver.
        //获取事件的触控点集合
        final int oldPointerIdBits = event.getPointerIdBits();
        //根据事件触控点集合和期待触控点集合做运算得到新的触控点集合
        final int newPointerIdBits = oldPointerIdBits & desiredPointerIdBits;

        // If for some reason we ended up in an inconsistent state where it looks like we
        // might produce a motion event with no pointers in it, then drop the event.
        //新的触控点不存在的话派发失败
        if (newPointerIdBits == 0) {
            return false;
        }

        // If the number of pointers is the same and we don't need to perform any fancy
        // irreversible transformations, then we can reuse the motion event for this
        // dispatch as long as we are careful to revert any changes we make.
        // Otherwise we need to make a copy.
        final MotionEvent transformedEvent;
        //新触控点和老触控点相同
        if (newPointerIdBits == oldPointerIdBits) {
            //子视图为空或者具有单位矩阵(即没有进行过缩放、旋转或平移等变换)
            if (child == null || child.hasIdentityMatrix()) {
                if (child == null) {
                    //子视图为空 分发事件到viewGroup中
                    handled = super.dispatchTouchEvent(event);
                } else {
                    //子视图不为空并且由单位矩阵
                    //计算子视图坐标偏移量
                    final float offsetX = mScrollX - child.mLeft;
                    final float offsetY = mScrollY - child.mTop;
                    event.offsetLocation(offsetX, offsetY);
                    //发送事件到子view
                    handled = child.dispatchTouchEvent(event);
                    event.offsetLocation(-offsetX, -offsetY);
                }
                return handled;
            }
            transformedEvent = MotionEvent.obtain(event);
        } else {、
            //根据newPointerIdBits拆分event
            transformedEvent = event.split(newPointerIdBits);
        }

        // Perform any necessary transformations and dispatch.
        if (child == null) {
            //由ViewGroup处理事件
            handled = super.dispatchTouchEvent(transformedEvent);
        } else {
            //坐标转换适配子view
            final float offsetX = mScrollX - child.mLeft;
            final float offsetY = mScrollY - child.mTop;
            transformedEvent.offsetLocation(offsetX, offsetY);
            if (! child.hasIdentityMatrix()) {
                transformedEvent.transform(child.getInverseMatrix());
            }
            //事件派发给子View
            handled = child.dispatchTouchEvent(transformedEvent);
        }

        // Done.
        //回收transformedEvent
        transformedEvent.recycle();
        return handled;
    }

总结:
1.检查 even的Action是否为cancel,是的话直接发送cancel事件
2. 根据event的触控点集合和期待的触控点集合进行位运算获取新的触控点集合
3. 根据子视图是否存在以及子视图是否由单位矩阵
来决定事件的坐标是否需要转换成view坐标系坐标,事件是由父View处理还是子View处理/子ViewGroup
4. 派发完转换事件,回收转换事件
存在子View的情况,执行child.dispatchTouchEvent方法

接下来看下View的dispatchTouchEvent

    public boolean dispatchTouchEvent(MotionEvent event) {
        // If the event should be handled by accessibility focus first.
        if (event.isTargetAccessibilityFocus()) {
            // We don't have focus or no virtual descendant has it, do not handle the event.
            if (!isAccessibilityFocusedViewOrHost()) {
                return false;
            }
            // We have focus and got the event, then use normal event dispatch.
            event.setTargetAccessibilityFocus(false);
        }
        boolean result = false;

        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onTouchEvent(event, 0);
        }

        final int actionMasked = event.getActionMasked();
        if (actionMasked == MotionEvent.ACTION_DOWN) {
            // Defensive cleanup for new gesture
            stopNestedScroll();
        }
        //再确认一次视图是否被遮挡
        if (onFilterTouchEventForSecurity(event)) {
            if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
                result = true;
            }
            //noinspection SimplifiableIfStatement
            //这里检查mListenerInfo是否存在
            //mOnTouchListener是否存在
            //mViewFlags是ENABLED状态
            //上述条件满足执行li.mOnTouchListener.onTouch(this, event)
            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }
            //上述方式执行失败,执行onTouchEvent
            if (!result && onTouchEvent(event)) {
                result = true;
            }
        }

        if (!result && mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
        }

        // Clean up after nested scrolls if this is the end of a gesture;
        // also cancel it if we tried an ACTION_DOWN but we didn't want the rest
        // of the gesture.
        if (actionMasked == MotionEvent.ACTION_UP ||
                actionMasked == MotionEvent.ACTION_CANCEL ||
                (actionMasked == MotionEvent.ACTION_DOWN && !result)) {
            stopNestedScroll();
        }

        return result;
    }

事件处理顺序mOnTouchListener.onTouch(this, event) -> onTouchEvent(event) -> onLongclick -> onClick

总结 :
关于JAVA层事件的派发主要有三个方法
View/ViewGroup
dispatchTouchEvent 事件派发
onInterceptTouchEvent 事件拦截
onTouchEvent 事件处理

提出几点疑问

  1. onclick 事件都是在 ACTION_UP 以后才被调用的
  2. mOnTouchListener.onTouch(this, event) return true的话 是不会执行onClick事件
  3. 子 View 可以通过 requestDisallowInterceptTouchEvent 方法干预父 View 的事件分发过程 但是不包含down事件

接下来继续分析源码,同时也在分析源码中解开上述问题
上面View的dispatchTouchEvent方法会先检查li.mOnTouchListener.onTouch(this, event)是否为true,true的话直接返回,不会在执行onTouchEvent 中的onClick

如果是false的话执行 View.onTouchEvent方法

  public boolean onTouchEvent(MotionEvent event) {
        final float x = event.getX();
        final float y = event.getY();
        final int viewFlags = mViewFlags;
        final int action = event.getAction();

        final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE
                || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)
                || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE
   .......
   //支持点击
        if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {
            switch (action) {
                case MotionEvent.ACTION_UP:
                .....
                  if (!focusTaken) {
                                // Use a Runnable and post this rather than calling
                                // performClick directly. This lets other visual state
                                // of the view update before click actions start.
                                //ACTION_UP执行performClickInternal方法
                                if (mPerformClick == null) {
                                    mPerformClick = new PerformClick();
                                }
                                if (!post(mPerformClick)) {
                                    performClickInternal();
                                }
                            }
                        }

             case MotionEvent.ACTION_DOWN:
                     .......
                      else {
                        // Not inside a scrolling container, so show the feedback right away
                        setPressed(true, x, y);
                        checkForLongClick(
                                ViewConfiguration.getLongPressTimeout(),
                                x,
                                y,
                                TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS);
                    }
             case MotionEvent.ACTION_MOVE:
                    final boolean deepPress =
                            motionClassification == MotionEvent.CLASSIFICATION_DEEP_PRESS;
                    if (deepPress && hasPendingLongPressCallback()) {
                        // process the long click action immediately
                        removeLongPressCallback();
                        checkForLongClick(
                                0 /* send immediately */,
                                x,
                                y,
                                TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS);
                    }

                    break;
            }

            return true;
        }

可以看到事件只要进入到View的onTouchEvent方法,只要ViewFlag是支持CLICKABLE / LONG_CLICKABLE 事件就一定会被处理且返回true
在ACTION_UP的时候执行performClickInternal函数
在ACTION_MOVE/ ACRION_DOWN 会执行checkForLongClick

接下来看下performClickInternal函数

    private boolean performClickInternal() {
        // Must notify autofill manager before performing the click actions to avoid scenarios where
        // the app has a click listener that changes the state of views the autofill service might
        // be interested on.
        notifyAutofillManagerOnClick();
        //执行performClick函数
        return performClick();
    }

接下来看performClick函数

    public boolean performClick() {
        // We still need to call this method to handle the cases where performClick() was called
        // externally, instead of through performClickInternal()
        notifyAutofillManagerOnClick();

        final boolean result;
        final ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnClickListener != null) {
            //ListenerInfo和li.mOnClickListener不为空
            //播放click声音
            playSoundEffect(SoundEffectConstants.CLICK);
            //执行View的onclick函数
            li.mOnClickListener.onClick(this);
            result = true;
        } else {
            result = false;
        }

        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);

        notifyEnterOrExitForAutoFillIfNeeded(true);

        return result;
    }

接下来看checkForLongClick函数


    private void checkForLongClick(long delay, float x, float y, int classification) {
        if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) {
            mHasPerformedLongPress = false;

            if (mPendingCheckForLongPress == null) {
                mPendingCheckForLongPress = new CheckForLongPress();
            }
            mPendingCheckForLongPress.setAnchor(x, y);
            mPendingCheckForLongPress.rememberWindowAttachCount();
            mPendingCheckForLongPress.rememberPressedState();
            mPendingCheckForLongPress.setClassification(classification);
            postDelayed(mPendingCheckForLongPress, delay);
        }
    }

构建CheckForLongPress对象 延时post mPendingCheckForLongPress runnable函数

        @Override
        public void run() {
            if ((mOriginalPressedState == isPressed()) && (mParent != null)
                    && mOriginalWindowAttachCount == mWindowAttachCount) {
                recordGestureClassification(mClassification);
                if (performLongClick(mX, mY)) {
                    mHasPerformedLongPress = true;
                }
            }
        }

runnable的run方法 执行performLongClick函数
最后会执行到该函数

    private boolean performLongClickInternal(float x, float y) {
        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);

        boolean handled = false;
        final ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnLongClickListener != null) {
            handled = li.mOnLongClickListener.onLongClick(View.this);
        }

可以看到这里执行li.mOnLongClickListener.onLongClick(View.this)

这里的ListenerInfo.mOnLongClickListener是从哪里出现的

    public void setOnClickListener(@Nullable OnClickListener l) {
        if (!isClickable()) {
            setClickable(true);
        }
        getListenerInfo().mOnClickListener = l;
    }


可以看到View的setOnClickListener这里实际就是我们应用自己定义实现的OnClickListener对象,同样onClick / onLongClick也会回调到我们自己重写的方法中

👀关注公众号:Android老皮!!!欢迎大家来找我探讨交流👀