Android13 Input -view 事件分發(fā)

View事件分發(fā)

InputDispatcher通過(guò)與對(duì)應(yīng)窗口建立連接通道,將事件信息封裝成InputMessgae,通過(guò)InputChannel將信息發(fā)送到窗口端socket,looper監(jiān)聽(tīng)到fd有數(shù)據(jù)寫入,執(zhí)行NativeInputEventReceiver::handleEvent函數(shù),讀取窗口socket端數(shù)據(jù),在返回到j(luò)ava端進(jìn)行處理

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

執(zhí)行InputEventReceiver的重寫函數(shù)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 創(chuàng)建processedEvents集合
2 processInputEventForCompatibility考慮在發(fā)送app前做適配
3 判斷適配處理后的事件是否存在
不存在代表事件處理完畢 將事件反饋給到InputDispatcher
存在 遍歷processedEvents執(zhí)行enqueueInputEvent入隊(duì)派發(fā)
4 適配處理后的事件不存在 代表當(dāng)前事件不需要適配,直接執(zhí)行enqueueInputEvent入隊(duì)派發(fā)

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能否轉(zhuǎn)為MotionEvent
3 判斷MotionEvent.action是MotionEvent.ACTION_CANCEL
EventLog寫入cancel事件
4 判斷KeyEvent.action是KeyEvent.isCanceled
EventLog寫入cancel事件
5 input事件隊(duì)列追加事件
6 這里processImmediately為true 執(zhí)行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 從緩存事件隊(duì)列頭部取出事件
2 緩存事件數(shù)量-1
3 deliverInputEvent 分發(fā)事件

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 驗(yàn)證輸入事件的一致性。如果事件存在異常,則會(huì)拋出異常并終止程序的執(zhí)行
2 輸入事件的處理流程包括多個(gè) Stage,每個(gè) Stage 負(fù)責(zé)一些特定的任務(wù),shouldSendToSynthesizer用于處理,mSyntheticInputStage主要負(fù)責(zé)處理需要進(jìn)行輸入法合成的輸入事件
3 q.shouldSendToSynthesizer() false 代表不是合成的輸入事件,根據(jù)shouldSkipIme確認(rèn)選擇mFirstPostImeInputStage 處理輸入法事件還是mFirstInputStage處理輸入事件的第一階段
4 判斷mEvent的類型是否為KeyEvent,是的話執(zhí)行 mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);
5 上述選擇的stage不為空,檢查窗口焦點(diǎn)是否發(fā)生變化來(lái)調(diào)整事件的派發(fā),之后調(diào)用Stage.deliver來(lái)派發(fā)
在研究Stage.deliver派發(fā)事件前要先了解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 可以看到在執(zhí)行setView方法
2 構(gòu)建了7個(gè)階段
AsyncInputStage:這個(gè)階段是輸入系統(tǒng)的異步處理階段。在用戶輸入事件發(fā)生后,首先會(huì)經(jīng)過(guò)硬件驅(qū)動(dòng)層的處理,然后傳遞給應(yīng)用程序的主線程。在主線程中,輸入事件會(huì)被封裝并發(fā)送到 AsyncInputStage 進(jìn)行異步處理。這個(gè)階段的任務(wù)包括事件的解析、轉(zhuǎn)換、分發(fā)等操作,確保輸入事件能夠被正確地傳遞給相應(yīng)的目標(biāo)視圖進(jìn)行處理。
第一階段:
SyntheticInputStage 是 Android 系統(tǒng)中的一個(gè)輸入階段,它屬于系統(tǒng)輸入處理的一部分。具體來(lái)說(shuō),SyntheticInputStage 用于處理合成輸入事件。

在 Android 中,合成輸入事件是由系統(tǒng)模擬生成的輸入事件,而不是由用戶實(shí)際觸發(fā)的。合成輸入事件可以用于模擬用戶操作,例如自動(dòng)化測(cè)試、輔助功能等場(chǎng)景。SyntheticInputStage 負(fù)責(zé)接收和處理這些合成輸入事件,并將它們傳遞給目標(biāo)視圖進(jìn)行相應(yīng)的處理。

在 SyntheticInputStage 階段,系統(tǒng)會(huì)將合成輸入事件按照特定的順序進(jìn)行處理,通常包括以下幾個(gè)步驟:

合成輸入事件的生成:系統(tǒng)根據(jù)需要生成合成輸入事件,這些事件可以模擬用戶的點(diǎn)擊、滑動(dòng)、長(zhǎng)按等操作。生成合成輸入事件的方式可以通過(guò)調(diào)用相應(yīng)的 API 或使用相關(guān)的工具類來(lái)實(shí)現(xiàn)。

合成輸入事件的分發(fā):生成的合成輸入事件會(huì)被系統(tǒng)分發(fā)到相應(yīng)的 SyntheticInputStage 階段進(jìn)行處理。系統(tǒng)會(huì)按照一定的規(guī)則確定目標(biāo)視圖,然后將合成輸入事件傳遞給目標(biāo)視圖進(jìn)行處理。

合成輸入事件的處理:SyntheticInputStage 接收到合成輸入事件后,會(huì)將事件傳遞給目標(biāo)視圖進(jìn)行處理。目標(biāo)視圖可以是應(yīng)用程序中的任何視圖,例如按鈕、文本框等。目標(biāo)視圖根據(jù)接收到的合成輸入事件來(lái)執(zhí)行相應(yīng)的操作,如執(zhí)行點(diǎn)擊操作、滾動(dòng)操作等。

需要注意的是,SyntheticInputStage 階段是系統(tǒng)的一部分,一般情況下開發(fā)者無(wú)需直接操作或干預(yù)該階段的過(guò)程。這個(gè)階段在 Android 系統(tǒng)內(nèi)部進(jìn)行,主要目的是處理合成輸入事件,以模擬用戶操作或?qū)崿F(xiàn)輔助功能。
第二階段:
ViewPostImeInputStage 是 Android 系統(tǒng)中的一個(gè)輸入階段,它屬于系統(tǒng)輸入處理的一部分。具體來(lái)說(shuō),ViewPostImeInputStage 用于處理 IME(輸入法)相關(guān)的輸入事件。

在 Android 中,IME 輸入事件是由輸入法軟件發(fā)送給應(yīng)用程序的。當(dāng)用戶在文本框或其他可編輯視圖中進(jìn)行輸入時(shí),輸入法軟件會(huì)生成相應(yīng)的輸入事件,并將其發(fā)送到應(yīng)用程序中。ViewPostImeInputStage 階段負(fù)責(zé)接收和處理這些輸入事件,并將它們傳遞給目標(biāo)視圖進(jìn)行相應(yīng)的處理。

在 ViewPostImeInputStage 階段,系統(tǒng)會(huì)按照以下步驟處理 IME 相關(guān)的輸入事件:

IME 輸入事件的生成:當(dāng)用戶在輸入法軟件中輸入文字時(shí),輸入法軟件會(huì)生成相應(yīng)的輸入事件,如文本變化事件、光標(biāo)位置變化事件等。

IME 輸入事件的分發(fā):輸入法軟件將生成的輸入事件發(fā)送到當(dāng)前活動(dòng)的應(yīng)用程序中。系統(tǒng)會(huì)將這些輸入事件分發(fā)給適當(dāng)?shù)?ViewPostImeInputStage 階段進(jìn)行處理。

IME 輸入事件的處理:ViewPostImeInputStage 接收到 IME 輸入事件后,會(huì)將事件傳遞給目標(biāo)視圖進(jìn)行處理。目標(biāo)視圖通常是當(dāng)前正在與用戶交互的文本框或可編輯視圖。目標(biāo)視圖根據(jù)接收到的輸入事件來(lái)更新文本內(nèi)容、光標(biāo)位置等,并可能觸發(fā)相應(yīng)的監(jiān)聽(tīng)器或回調(diào)方法。

需要注意的是,ViewPostImeInputStage 階段是系統(tǒng)的一部分,開發(fā)者無(wú)需直接操作或干預(yù)該階段的過(guò)程。這個(gè)階段在 Android 系統(tǒng)內(nèi)部進(jìn)行,主要目的是處理與輸入法相關(guān)的輸入事件,以確保用戶的輸入能夠正確地顯示和處理。
第三階段:
nativePostImeStage是在提到原生(native)層面的輸入處理,可以理解為與輸入法相關(guān)的底層操作和事件。

在底層的原生開發(fā)中,涉及到輸入法的處理通常包括以下幾個(gè)方面:

輸入法管理器(InputMethodManager):在原生開發(fā)中,可以使用輸入法管理器來(lái)控制輸入法的顯示、隱藏以及切換。通過(guò)輸入法管理器,可以獲取當(dāng)前的輸入法信息、打開或關(guān)閉輸入法窗口、獲取輸入法視圖等。

輸入法事件處理:原生開發(fā)可以處理與輸入法相關(guān)的事件,例如鍵盤按鍵事件(KeyEvent)、觸摸事件(MotionEvent)等。通過(guò)監(jiān)聽(tīng)和處理這些事件,可以實(shí)現(xiàn)與輸入法交互的功能,如捕獲按鍵輸入、響應(yīng)觸摸操作等。

輸入框處理:原生開發(fā)還可以針對(duì)輸入框進(jìn)行處理,包括輸入框的創(chuàng)建、位置和大小的調(diào)整、內(nèi)容的顯示和編輯等。通過(guò)與輸入框的交互,可以實(shí)現(xiàn)與用戶的輸入交互和數(shù)據(jù)處理。
第四階段:

接下來(lái)我們看其中一個(gè)stage的構(gòu)造函數(shù)

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

這里可以看到將ViewPostImeInputStage關(guān)聯(lián)的下一階段stage,放到父類InputStage的構(gòu)造函數(shù)中

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

這里看到下個(gè)階段的stage賦值到mNext中
那么在執(zhí)行父類InputStage的方法時(shí)比如

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

這里調(diào)用 mNext.deliver(q)就來(lái)到了下個(gè)階段的deliver函數(shù)中

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

在這里執(zhí)行下一個(gè)階段的onProcess函數(shù),將處理結(jié)果和事件給到
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);
            }
        }

這里根據(jù)處理結(jié)果執(zhí)行不同函數(shù) 關(guān)于apply來(lái)說(shuō)由于stage不同分為了同步異步倆個(gè)部分 這里主要看同步

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

執(zhí)行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);
            }
        }

這里可以看到要分發(fā)到下下個(gè)階段了,同時(shí)如果所有階段都執(zhí)行完就執(zhí)行finishInputEvent給InputDispatcher反饋了
再看下finish函數(shù)

        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 ,分發(fā)下個(gè)階段,下個(gè)階段一看事件已經(jīng)處理完了,那直接跳過(guò)平臺(tái)來(lái)給InputDispatcher反饋

經(jīng)過(guò)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 當(dāng)前是KeyEvent執(zhí)行processKeyEvent
2 source是InputDevice.SOURCE_CLASS_POINTER 執(zhí)行processPointerEvent
3 source是InputDevice.SOURCE_CLASS_TRACKBALL執(zhí)行processTrackballEvent事件
4 其他執(zhí)行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 執(zhí)行 mView.dispatchPointerEvent(event)
3 根據(jù)結(jié)果確認(rèn)當(dāng)前是FINISH_HANDLED還是FORWARD

View.java
    public final boolean dispatchPointerEvent(MotionEvent event) {
        if (event.isTouchEvent()) {
            return dispatchTouchEvent(event);
        } else {
            return dispatchGenericMotionEvent(event);
        }
    }

1 檢查事件是否為touch事件 是的話執(zhí)行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對(duì)象即窗口的Activity
2 執(zhí)行Activity的dispatchTouchEvent方法
關(guān)于為什么phoneWindow的callback對(duì)象即窗口的Activity

Activity.java
final void attach(......){
    ......
    mWindow = new PhoneWindow(this, window, activityConfigCallback);
    mWindow.setWindowControllerCallback(this);
    mWindow.setCallback(this); // 這里的 this 就是 Activity
    ......
}

接下來(lái)執(zhí)行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事件執(zhí)行onUserInteraction這個(gè)空方法,通知用戶,Activity已經(jīng)接收到事件了
2 當(dāng)前Activity的窗口執(zhí)行superDispatchTouchEvent方法,派發(fā)成功返回true
3 如果上述都失敗了,就執(zhí)行Activity的onTouchEvent方法

接下來(lái)看當(dāng)前Activity的窗口執(zhí)行superDispatchTouchEvent方法

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

1 執(zhí)行DecorView的superDispatchTouchEvent方法

接下來(lái)看DecorView的superDispatchTouchEvent方法

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

1 執(zhí)行父類的superDispatchTouchEvent方法,這里的super是ViewGroup

為什么這里的super是ViewGroup

public class DecorView extends FrameLayout

public class FrameLayout extends ViewGroup

1 可以看到最終的父類是ViewGroup
在查看ViewGroup的dispatchTouchEvent方法前,先做一個(gè)java端事件派發(fā)總結(jié):
可以看到在輸入事件通過(guò)NativeInputEventReciver的InputConsumer從InputChannel中讀出由JNI ->java端 ->ViewRootImpl -> InputStage -> DecorView -> Activity -> PhoneWindow -> DecorView -> ViewGroup

接下來(lái)看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;
        // 判斷此次觸摸事件是否被過(guò)濾掉,條件由兩個(gè) flag 決定,F(xiàn)ILTER_TOUCHES_WHEN_OBSCURED
        // 和 MotionEvent.FLAG_WINDOW_IS_OBSCURED,這兩個(gè) flag 用來(lái)表示
        // 當(dāng)前接收觸摸事件的 View 是否被遮擋或者隱藏,只有未被遮擋或隱藏才能
        // 進(jìn)一步處理事件

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

            // Handle an initial down.
            //事件action為MotionEvent.ACTION_DOWN代表一次新的事件序列到來(lái),需要清空上一次
            //事件序列的相關(guān)狀態(tài)
            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(接收事件的目標(biāo))不為空
                final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
                //檢查mGroupFlags是否為FLAG_DISALLOW_INTERCEPT
                //FLAG_DISALLOW_INTERCEPT這個(gè)為不允許攔截事件Flag
                if (!disallowIntercept) {
                    //父view調(diào)用onInterceptTouchEvent攔截事件
                    intercepted = onInterceptTouchEvent(ev);
                    ev.setAction(action); // restore action in case it was changed
                } else {
                    //設(shè)置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.
                //當(dāng)前Action不是ACTION_DOWN或者沒(méi)有mFirstTouchTarget(接收事件的目標(biāo))
                //事件要被攔截
                intercepted = true;
            }
            // Check for cancelation.
            //resetCancelNextUpFlag(this)為true或者Action為ACTION_CANCEL
            //會(huì)設(shè)置canceled為true
            //resetCancelNextUpFlag方法指的View是否存在PFLAG_CANCEL_NEXT_UP_EVENT標(biāo)志
            final boolean canceled = resetCancelNextUpFlag(this)
                    || actionMasked == MotionEvent.ACTION_CANCEL;

            // Update list of touch targets for pointer down, if needed.
            //是否為鼠標(biāo)事件
            final boolean isMouseEvent = ev.getSource() == InputDevice.SOURCE_MOUSE;
            //mGroupFlags是否包含F(xiàn)LAG_SPLIT_MOTION_EVENTS并且不是鼠標(biāo)事件
            //檢查View是否支持事件拆分
            final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0
                    && !isMouseEvent;
            //定義新的接收事件的目標(biāo)
            TouchTarget newTouchTarget = null;
            //事件是否派發(fā)到新的接收事件的目標(biāo)的標(biāo)志位
            boolean alreadyDispatchedToNewTouchTarget = false;
                if (!canceled && !intercepted) {
                //進(jìn)入該判斷的事件 未被取消并且攔截

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

                if (actionMasked == MotionEvent.ACTION_DOWN
                        || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
                        || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
                    //新事件序列開始的行為則進(jìn)入該判斷 
                    //獲取事件Index
                    final int actionIndex = ev.getActionIndex(); // always 0 for down
                    //根據(jù)是否支持事件拆分獲取觸控點(diǎn)位
                    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.
                    //移除上次事件序列的觸控點(diǎn)位
                    removePointersFromTouchTargets(idBitsToAssign);
                    //獲取子視圖數(shù)量
                    final int childrenCount = mChildrenCount;
                    //新的接收事件目標(biāo)為空并且子視圖不為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.
                        //獲取預(yù)排續(xù)(按照Z(yǔ)order順序)子view集合
                        final ArrayList<View> preorderedList = buildTouchDispatchChildList();
                        //是否滿足子view集合自定義排序
                        final boolean customOrder = preorderedList == null
                                && isChildrenDrawingOrderEnabled();
                        //子view數(shù)組
                        final View[] children = mChildren;
                        //根據(jù)zOrder由高到底遍歷預(yù)排續(xù)view數(shù)組
                        for (int i = childrenCount - 1; i >= 0; i--) {
                            //獲取子view的index
                            final int childIndex = getAndVerifyPreorderedIndex(
                                    childrenCount, i, customOrder);
                            //獲取子view對(duì)象
                            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;
                            }
                            //子視圖是否可以接收事件或者當(dāng)前事件的坐標(biāo)是否在子視圖中
                            if (!child.canReceivePointerEvents()
                                    || !isTransformedTouchPointInView(x, y, child, null)) {
                                //不滿足條件則開啟下一個(gè)View的遍歷循環(huán)
                                ev.setTargetAccessibilityFocus(false);
                                continue;
                            }
                            //如果找到了事件所在的子視圖
                            //getTouchTarget會(huì)根據(jù)子視圖獲取的newTouchTarget
                            //newTouchTarget不為空代表子視圖之前處理過(guò)事件(多指觸碰)
                            //對(duì)于單指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.
                                //更新接收事件目標(biāo)中觸控位的值
                                newTouchTarget.pointerIdBits |= idBitsToAssign;
                                //跳出循環(huán) 當(dāng)前已找到對(duì)應(yīng)處理該事件的view
                                break;
                            }
                            //如果有設(shè)置 PFLAG_CANCEL_NEXT_UP_EVENT,在此清除
                            resetCancelNextUpFlag(child);
                            //dispatchTransformedTouchEvent方法為事件找到真正處理它的子控件View
                            if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
                                // Child wants to receive touch within its bounds.
                                //事件派發(fā)成功找到子控件View
                                //記錄最后一次down時(shí)間
                                mLastTouchDownTime = ev.getDownTime();
                                //存在預(yù)排序view集合
                                if (preorderedList != null) {
                                    // childIndex points into presorted list, find original index
                                    for (int j = 0; j < childrenCount; j++) {
                                        //遍歷預(yù)排續(xù)View數(shù)組獲取處理該事件的View的childIndex
                                        if (children[childIndex] == mChildren[j]) {
                                            mLastTouchDownIndex = j;
                                            break;
                                        }
                                    }
                                } else {
                                    //最后一次down事件index是原始子視圖的index
                                    mLastTouchDownIndex = childIndex;
                                }
                                //獲取最后一次down事件的 x y坐標(biāo)
                                mLastTouchDownX = ev.getX();
                                mLastTouchDownY = ev.getY();
                                //根據(jù)子視圖和觸控點(diǎn)創(chuàng)建newTouchTarget
                                newTouchTarget = addTouchTarget(child, idBitsToAssign);
                                //flag設(shè)置為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);
                        }
                        //清空預(yù)排序view集合
                        if (preorderedList != null) preorderedList.clear();
                    }
                    //如果沒(méi)找到事件所對(duì)應(yīng)的子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.
                //如果沒(méi)有觸摸目標(biāo),則將觸摸事件視為普通的視圖
                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) {
                    //保存下一個(gè)TouchTarget到next
                    final TouchTarget next = target.next;
                    if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
                        //如果已經(jīng)將事件派發(fā)到新的TouchTarget
                        handled = true;
                    } else {
                        //檢查View是否包含PFLAG_CANCEL_NEXT_UP_EVENT這個(gè)flag
                        final boolean cancelChild = resetCancelNextUpFlag(target.child)
                                || intercepted;
                        //將事件派發(fā)到目標(biāo)視圖中,這里一般是處理Move事件
                        if (dispatchTransformedTouchEvent(ev, cancelChild,
                                target.child, target.pointerIdBits)) {
                            //處理成功
                            handled = true;
                        }
                        //如果需要去掉子視圖,也需要調(diào)整鏈表的中該視圖對(duì)于的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) {
                //可拆分并且存在多指抬起
                //根據(jù)actionIndex獲取觸控點(diǎn)idBitsToRemove然后調(diào)整touchTarget的觸控點(diǎn)
                final int actionIndex = ev.getActionIndex();
                final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
                removePointersFromTouchTargets(idBitsToRemove);
            }
        }

總結(jié):
1 關(guān)于ViewGroup的事件派發(fā),首先onFilterTouchEventForSecurity方法檢查接收事件的View是否被遮擋,遮擋的話是要cancel的,
2 對(duì)于一次down行為,可以理解為一次新的事件序列,要清空TouchTarget鏈表。
3 對(duì)于一次down行為,一定會(huì)被ViewGroup攔截進(jìn)行onInterceptTouchEvent方法檢查是否攔截成功,對(duì)于單指操作來(lái)說(shuō)一旦down事件被攔截 該次事件序列的MOVE UP都會(huì)被攔截但不在執(zhí)行onInterceptTouchEvent方法,子 View 可以通過(guò) requestDisallowInterceptTouchEvent 方法請(qǐng)求父 View 不要攔截
同樣關(guān)于onInterceptTouchEvent方法方法也不一定會(huì)攔截掉down事件,也要做條件判斷,后續(xù)細(xì)看
4 檢查事件是否被cancel
5 檢查事件資源是否為鼠標(biāo)事件
6 檢查事件是否可拆分
7 定義事件派發(fā)標(biāo)志位
8 在事件不被cancel和intercept時(shí),單指Down行為,多指可拆分的Pointer_Down行為,以及鼠標(biāo)懸浮MOVE行為,這種新事件序列行為
以單指Down行為來(lái)說(shuō)
首先獲取 x,y坐標(biāo)
獲取Zorder預(yù)排續(xù)的View集合
遍歷View集合 檢查View是否可以接收事件,事件坐標(biāo)是否在View內(nèi)
不滿足 輪詢下一個(gè)View
滿足 執(zhí)行dispatchTransformedTouchEvent方法 派發(fā)給子View處理該事件
處理成功,構(gòu)建newTouchTarget來(lái)保存View,后續(xù)事件序列的事件可以直接派發(fā)到該View
如果沒(méi)找到子View處理該事件,android的機(jī)制是讓最近一次的TouchTarget來(lái)處理該事件
接下來(lái)單指Move行為
就執(zhí)行下述mFirstTouchTarget鏈表遍歷,找到合適的子View處理行為事件
接下來(lái)單指Up行為
執(zhí)行resetTouchState()方法 清空鏈表

接下來(lái)看一下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 如果事件為空 根據(jù)當(dāng)前時(shí)間生成Cancel事件,設(shè)置syntheticEvent為true
3 遍歷mFirstTouchTarget鏈表,執(zhí)行resetCancelNextUpFlag方法,向上次事件序列的子View發(fā)送cancel事件
4 清空touchTarget鏈表

接下來(lái)先看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

接下來(lái)看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;
        }

      
    }

因?yàn)?上述中cancel為true會(huì)向View發(fā)送cancel事件取消上次事件序列

接下來(lái)看下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 觸控目標(biāo)列表 將觸控目標(biāo)的view設(shè)置為null。

接下來(lái)看

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

接下來(lái)看下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;
    }

可以看到事件滿足下述條件才會(huì)返回true或者
或者actionMasked != MotionEvent.ACTION_DOWN才會(huì)設(shè)置 ,如果onInterceptTouchEvent失敗 intercepted = false。

接下來(lái)看下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進(jìn)行比較,來(lái)清除TouchTarget鏈表的之前TouchTarget的pointerIdBits

接下來(lái)看下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派發(fā)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.
        //獲取事件的觸控點(diǎn)集合
        final int oldPointerIdBits = event.getPointerIdBits();
        //根據(jù)事件觸控點(diǎn)集合和期待觸控點(diǎn)集合做運(yùn)算得到新的觸控點(diǎn)集合
        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.
        //新的觸控點(diǎn)不存在的話派發(fā)失敗
        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;
        //新觸控點(diǎn)和老觸控點(diǎn)相同
        if (newPointerIdBits == oldPointerIdBits) {
            //子視圖為空或者具有單位矩陣(即沒(méi)有進(jìn)行過(guò)縮放、旋轉(zhuǎn)或平移等變換)
            if (child == null || child.hasIdentityMatrix()) {
                if (child == null) {
                    //子視圖為空 分發(fā)事件到viewGroup中
                    handled = super.dispatchTouchEvent(event);
                } else {
                    //子視圖不為空并且由單位矩陣
                    //計(jì)算子視圖坐標(biāo)偏移量
                    final float offsetX = mScrollX - child.mLeft;
                    final float offsetY = mScrollY - child.mTop;
                    event.offsetLocation(offsetX, offsetY);
                    //發(fā)送事件到子view
                    handled = child.dispatchTouchEvent(event);
                    event.offsetLocation(-offsetX, -offsetY);
                }
                return handled;
            }
            transformedEvent = MotionEvent.obtain(event);
        } else {、
            //根據(jù)newPointerIdBits拆分event
            transformedEvent = event.split(newPointerIdBits);
        }

        // Perform any necessary transformations and dispatch.
        if (child == null) {
            //由ViewGroup處理事件
            handled = super.dispatchTouchEvent(transformedEvent);
        } else {
            //坐標(biāo)轉(zhuǎn)換適配子view
            final float offsetX = mScrollX - child.mLeft;
            final float offsetY = mScrollY - child.mTop;
            transformedEvent.offsetLocation(offsetX, offsetY);
            if (! child.hasIdentityMatrix()) {
                transformedEvent.transform(child.getInverseMatrix());
            }
            //事件派發(fā)給子View
            handled = child.dispatchTouchEvent(transformedEvent);
        }

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

總結(jié):
1檢查 even的Action是否為cancel,是的話直接發(fā)送cancel事件
2 根據(jù)event的觸控點(diǎn)集合和期待的觸控點(diǎn)集合進(jìn)行位運(yùn)算獲取新的觸控點(diǎn)集合
3 根據(jù)子視圖是否存在以及子視圖是否由單位矩陣
來(lái)決定事件的坐標(biāo)是否需要轉(zhuǎn)換成view坐標(biāo)系坐標(biāo),事件是由父View處理還是子View處理/子ViewGroup
4 派發(fā)完轉(zhuǎn)換事件,回收轉(zhuǎn)換事件
存在子View的情況,執(zhí)行child.dispatchTouchEvent方法

接下來(lái)看下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();
        }
        //再確認(rèn)一次視圖是否被遮擋
        if (onFilterTouchEventForSecurity(event)) {
            if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
                result = true;
            }
            //noinspection SimplifiableIfStatement
            //這里檢查mListenerInfo是否存在
            //mOnTouchListener是否存在
            //mViewFlags是ENABLED狀態(tài)
            //上述條件滿足執(zhí)行l(wèi)i.mOnTouchListener.onTouch(this, event)
            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }
            //上述方式執(zhí)行失敗,執(zhí)行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

總結(jié) :
關(guān)于JAVA層事件的派發(fā)主要有三個(gè)方法
View/ViewGroup
dispatchTouchEvent 事件派發(fā)
onInterceptTouchEvent 事件攔截
onTouchEvent 事件處理

提出幾點(diǎn)疑問(wèn)
1 onclick 事件都是在 ACTION_UP 以后才被調(diào)用的
2 mOnTouchListener.onTouch(this, event) return true的話 是不會(huì)執(zhí)行onClick事件
3 子 View 可以通過(guò) requestDisallowInterceptTouchEvent 方法干預(yù)父 View 的事件分發(fā)過(guò)程 但是不包含down事件

接下來(lái)繼續(xù)分析源碼,同時(shí)也在分析源碼中解開上述問(wèn)題
上面View的dispatchTouchEvent方法會(huì)先檢查li.mOnTouchListener.onTouch(this, event)是否為true,true的話直接返回,不會(huì)在執(zhí)行onTouchEvent 中的onClick

如果是false的話執(zhí)行 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
   .......
   //支持點(diǎn)擊
        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執(zhí)行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;
        }

可以看到事件只要進(jìn)入到View的onTouchEvent方法,只要ViewFlag是支持CLICKABLE / LONG_CLICKABLE 事件就一定會(huì)被處理且返回true
在ACTION_UP的時(shí)候執(zhí)行performClickInternal函數(shù)
在ACTION_MOVE/ ACRION_DOWN 會(huì)執(zhí)行checkForLongClick

接下來(lái)看下performClickInternal函數(shù)

    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();
        //執(zhí)行performClick函數(shù)
        return performClick();
    }

接下來(lái)看performClick函數(shù)

    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);
            //執(zhí)行View的onclick函數(shù)
            li.mOnClickListener.onClick(this);
            result = true;
        } else {
            result = false;
        }

        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);

        notifyEnterOrExitForAutoFillIfNeeded(true);

        return result;
    }

接下來(lái)看checkForLongClick函數(shù)


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

構(gòu)建CheckForLongPress對(duì)象 延時(shí)post mPendingCheckForLongPress runnable函數(shù)

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

runnable的run方法 執(zhí)行performLongClick函數(shù)
最后會(huì)執(zhí)行到該函數(shù)

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

可以看到這里執(zhí)行l(wèi)i.mOnLongClickListener.onLongClick(View.this)

這里的ListenerInfo.mOnLongClickListener是從哪里出現(xiàn)的

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

可以看到View的setOnClickListener這里實(shí)際就是我們應(yīng)用自己定義實(shí)現(xiàn)的OnClickListener對(duì)象,同樣onClick / onLongClick也會(huì)回調(diào)到我們自己重寫的方法中

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容