美文网首页Android
Android事件分发流程(android9.0)

Android事件分发流程(android9.0)

作者: android_coder | 来源:发表于2019-05-01 12:12 被阅读0次

    从手触摸到屏幕开始

    当屏幕被触摸之后,linux内核会将屏幕产生的触摸事件封装为event保存到/dev/input/event[x]节点下,接着系统创建的InputReaderThread线程Loop起来让EventHub调用getEvent不断的从/dev/input/节点下读取输入事件,然后InputReader线程将从EventHub读取的事件交给InputDispatch,InputDispatch则将事件分发到x需要的地方,譬如ViewRootImpl的WindowInputEventReceiver,这部分的逻辑主要是c++实现的,事件分发到ViewRootImpl之后也就是分发到了框架层,后续的事件就会通过一系列分发传递给decorView,然后传递给PhoneWindow,后续又回到DecorView,然后从这个顶级的view树节点向下分发

    1.0Decorview的添加过程

    不管是activity,dialog还是PopupWindow,其窗口的添加过程最终都是调用windowmanager的addView来实现的,windowmanager是一个接口,其最终是调用windowmanagerglobal的addView来实现的

                root = new ViewRootImpl(view.getContext(), display);//创建一个ViewRootImpl对象
                view.setLayoutParams(wparams);
                mViews.add(view);
                mRoots.add(root);
                mParams.add(wparams);
                // do this last because it fires off messages to start doing things
                try {
                    root.setView(view, wparams, panelParentView);//调用setView方法
                } catch (RuntimeException e) {
                    // BadTokenException or InvalidDisplayException, clean up.
                    if (index >= 0) {
                        removeViewLocked(index, true);//异常处理操作
                    }
                    throw e;
                }
    

    1.1ViewRootImpl的setView方法

                    requestLayout();//请求布局
                    if ((mWindowAttributes.inputFeatures
                            & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                        mInputChannel = new InputChannel();//创建InputChannel对象
                    }
                    mForceDecorViewVisibility = (mWindowAttributes.privateFlags
                            & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
                    try {
                        mOrigWindowType = mWindowAttributes.type;
                        mAttachInfo.mRecomputeGlobalAttributes = true;
                        collectViewAttributes();
                        res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,//调用windowsession的addToDisplay方法
                                getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
                                mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                                mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
                    } catch (RemoteException e) {
                        mAdded = false;
                        mView = null;
                        mAttachInfo.mRootView = null;
                        mInputChannel = null;
                        mFallbackEventHandler.setView(null);
                        unscheduleTraversals();
                        setAccessibilityFocus(null, null);
                        throw new RuntimeException("Adding window failed", e);
                    } finally {
                        if (restore) {
                            attrs.restore();
                        }
                    }
    

    接着关注下半部分

    if (mInputChannel != null) {//如果inputChannel不为空的时候
                        if (mInputQueueCallback != null) {
                            mInputQueue = new InputQueue();
                            mInputQueueCallback.onInputQueueCreated(mInputQueue);
                        }
                        mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
                                Looper.myLooper());
                    }
    
                    view.assignParent(this);
                    mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
                    mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
    
                    if (mAccessibilityManager.isEnabled()) {
                        mAccessibilityInteractionConnectionManager.ensureConnection();
                    }
    
                    if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
                        view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
                    }
    
                    // Set up the input pipeline.
                    CharSequence counterSuffix = attrs.getTitle();
                    mSyntheticInputStage = new SyntheticInputStage();
                    InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);//创建InputStage对象
                    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;
    

    从上面的代码我们看到创建了两个对象WindowInputEventReceiver和InputStage对象

    1.2从WindowInputEventReceiver开始

    WindowInputEventReceiver是ViewRootImpl的内部类

          final class WindowInputEventReceiver extends InputEventReceiver {
            public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
                super(inputChannel, looper);
            }
            @Override
            public void onInputEvent(InputEvent event, int displayId) {
                enqueueInputEvent(event, this, 0, true);
            }
            @Override
            public void onBatchedInputEventPending() {
                if (mUnbufferedInputDispatch) {
                    super.onBatchedInputEventPending();
                } else {
                    scheduleConsumeBatchedInput();
                }
            }
            @Override
            public void dispose() {
                unscheduleConsumeBatchedInput();
                super.dispose();
            }
    

    WindowInputEventReceiver是InputEventReceiver的子类

    1.3InputEventReceiver

        public InputEventReceiver(InputChannel inputChannel, Looper looper) {
            if (inputChannel == null) {
                throw new IllegalArgumentException("inputChannel must not be null");
            }
            if (looper == null) {
                throw new IllegalArgumentException("looper must not be null");
            }
            mInputChannel = inputChannel;
            mMessageQueue = looper.getQueue();//looper对应的消息队列
            mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
                    inputChannel, mMessageQueue);//会调用到android_view_InputEventReceiver.cpp
            mCloseGuard.open("dispose");
        }
    

    1.4InputEventReceiver.cpp

    static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
            jobject inputChannelObj, jobject messageQueueObj) {
        sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
                inputChannelObj);//将java对象转化为c++对象
        if (inputChannel == NULL) {
            jniThrowRuntimeException(env, "InputChannel is not initialized.");
            return 0;
        }
        sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
        if (messageQueue == NULL) {
            jniThrowRuntimeException(env, "MessageQueue is not initialized.");
            return 0;
        }
       //根据java层的inputchannel对象和Looper对象创建c++层的NativeInputEventReceiver 对象
        sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
                receiverWeak, inputChannel, messageQueue);
        status_t status = receiver->initialize();
        if (status) {
            String8 message;
            message.appendFormat("Failed to initialize input event receiver.  status=%d", status);
            jniThrowRuntimeException(env, message.string());
            return 0;
        }
        receiver->incStrong(gInputEventReceiverClassInfo.clazz); // retain a reference for the object
        return reinterpret_cast<jlong>(receiver.get());
    }
    

    NativeInputEventReceiver作用

    NativeInputEventReceiver::NativeInputEventReceiver(JNIEnv* env,
            jobject receiverWeak, const sp<InputChannel>& inputChannel,
            const sp<MessageQueue>& messageQueue) :
            mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
            mInputConsumer(inputChannel), mMessageQueue(messageQueue),
            mBatchedInputEventPending(false), mFdEvents(0) {
        if (kDebugDispatchCycle) {
            ALOGD("channel '%s' ~ Initializing input event receiver.", getInputChannelName().c_str());
        }
    }
    
    status_t NativeInputEventReceiver::initialize() {
        setFdEvents(ALOOPER_EVENT_INPUT);
        return OK;
    }
    

    NativeInputEventReceiver有一个私有的mInputConsumer变量,就是生成一个mInputConsumer并且调用initialize方法初始化,将inputChannel的fd挂载到looper中去监听事件,回调函数为handleEvent

    1.5setFdEvents的实现

    void NativeInputEventReceiver::setFdEvents(int events) {
        if (mFdEvents != events) {
            mFdEvents = events;
            int fd = mInputConsumer.getChannel()->getFd();
            if (events) {
                mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
            } else {
                mMessageQueue->getLooper()->removeFd(fd);
            }
        }
    }
    

    1.6handleEvent

    int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
        if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
            // This error typically occurs when the publisher has closed the input channel
            // as part of removing a window or finishing an IME session, in which case
            // the consumer will soon be disposed as well.
            if (kDebugDispatchCycle) {
                ALOGD("channel '%s' ~ Publisher closed input channel or an error occurred.  "
                        "events=0x%x", getInputChannelName().c_str(), events);
            }
            return 0; // remove the callback
        }
        if (events & ALOOPER_EVENT_INPUT) {
            JNIEnv* env = AndroidRuntime::getJNIEnv();
            status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL);
            mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
            return status == OK || status == NO_MEMORY ? 1 : 0;
        }
        if (events & ALOOPER_EVENT_OUTPUT) {
            for (size_t i = 0; i < mFinishQueue.size(); i++) {
                const Finish& finish = mFinishQueue.itemAt(i);
                status_t status = mInputConsumer.sendFinishedSignal(finish.seq, finish.handled);
                if (status) {
                    mFinishQueue.removeItemsAt(0, i);
                    if (status == WOULD_BLOCK) {
                        if (kDebugDispatchCycle) {
                            ALOGD("channel '%s' ~ Sent %zu queued finish events; %zu left.",
                                    getInputChannelName().c_str(), i, mFinishQueue.size());
                        }
                        return 1; // keep the callback, try again later
                    }
                    ALOGW("Failed to send finished signal on channel '%s'.  status=%d",
                            getInputChannelName().c_str(), status);
                    if (status != DEAD_OBJECT) {
                        JNIEnv* env = AndroidRuntime::getJNIEnv();
                        String8 message;
                        message.appendFormat("Failed to finish input event.  status=%d", status);
                        jniThrowRuntimeException(env, message.string());
                        mMessageQueue->raiseAndClearException(env, "finishInputEvent");
                    }
                    return 0; // remove the callback
                }
            }
            if (kDebugDispatchCycle) {
                ALOGD("channel '%s' ~ Sent %zu queued finish events; none left.",
                        getInputChannelName().c_str(), mFinishQueue.size());
            }
            mFinishQueue.clear();
            setFdEvents(ALOOPER_EVENT_INPUT);
            return 1;
        }
        ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event.  "
                "events=0x%x", getInputChannelName().c_str(), events);
        return 1;
    }
    

    1.7ConsumeEvent

    status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
            bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
        if (kDebugDispatchCycle) {
            ALOGD("channel '%s' ~ Consuming input events, consumeBatches=%s, frameTime=%" PRId64,
                    getInputChannelName().c_str(),
                    consumeBatches ? "true" : "false", frameTime);
        }
    
        if (consumeBatches) {
            mBatchedInputEventPending = false;
        }
        if (outConsumedBatch) {
            *outConsumedBatch = false;
        }
    
        ScopedLocalRef<jobject> receiverObj(env, NULL);
        bool skipCallbacks = false;
        for (;;) {
            uint32_t seq;
            InputEvent* inputEvent;
            int32_t displayId;
            status_t status = mInputConsumer.consume(&mInputEventFactory,
                    consumeBatches, frameTime, &seq, &inputEvent, &displayId);
            if (status) {
                if (status == WOULD_BLOCK) {
                    if (!skipCallbacks && !mBatchedInputEventPending
                            && mInputConsumer.hasPendingBatch()) {
                        // There is a pending batch.  Come back later.
                        if (!receiverObj.get()) {
                            receiverObj.reset(jniGetReferent(env, mReceiverWeakGlobal));
                            if (!receiverObj.get()) {
                                ALOGW("channel '%s' ~ Receiver object was finalized "
                                        "without being disposed.", getInputChannelName().c_str());
                                return DEAD_OBJECT;
                            }
                        }
                        mBatchedInputEventPending = true;
                        if (kDebugDispatchCycle) {
                            ALOGD("channel '%s' ~ Dispatching batched input event pending notification.",
                                    getInputChannelName().c_str());
                        }
                        env->CallVoidMethod(receiverObj.get(),
                                gInputEventReceiverClassInfo.dispatchBatchedInputEventPending);
                        if (env->ExceptionCheck()) {
                            ALOGE("Exception dispatching batched input events.");
                            mBatchedInputEventPending = false; // try again later
                        }
                    }
                    return OK;
                }
                ALOGE("channel '%s' ~ Failed to consume input event.  status=%d",
                        getInputChannelName().c_str(), status);
                return status;
            }
            assert(inputEvent);
            if (!skipCallbacks) {
                if (!receiverObj.get()) {
                    receiverObj.reset(jniGetReferent(env, mReceiverWeakGlobal));
                    if (!receiverObj.get()) {
                        ALOGW("channel '%s' ~ Receiver object was finalized "
                                "without being disposed.", getInputChannelName().c_str());
                        return DEAD_OBJECT;
                    }
                }
                jobject inputEventObj;
                switch (inputEvent->getType()) {
                case AINPUT_EVENT_TYPE_KEY:
                    if (kDebugDispatchCycle) {
                        ALOGD("channel '%s' ~ Received key event.", getInputChannelName().c_str());
                    }
                    inputEventObj = android_view_KeyEvent_fromNative(env,
                            static_cast<KeyEvent*>(inputEvent));
                    break;
                case AINPUT_EVENT_TYPE_MOTION: {
                    if (kDebugDispatchCycle) {
                        ALOGD("channel '%s' ~ Received motion event.", getInputChannelName().c_str());
                    }
                    MotionEvent* motionEvent = static_cast<MotionEvent*>(inputEvent);
                    if ((motionEvent->getAction() & AMOTION_EVENT_ACTION_MOVE) && outConsumedBatch) {
                        *outConsumedBatch = true;
                    }
                    inputEventObj = android_view_MotionEvent_obtainAsCopy(env, motionEvent);
                    break;
                }
                default:
                    assert(false); // InputConsumer should prevent this from ever happening
                    inputEventObj = NULL;
                }
                if (inputEventObj) {
                    if (kDebugDispatchCycle) {
                        ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName().c_str());
                    }
                    env->CallVoidMethod(receiverObj.get(),
                            gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj,
                            displayId);//回调java层的dispatchInputEvent方法
                    if (env->ExceptionCheck()) {
                        ALOGE("Exception dispatching input event.");
                        skipCallbacks = true;
                    }
                    env->DeleteLocalRef(inputEventObj);
                } else {
                    ALOGW("channel '%s' ~ Failed to obtain event object.",
                            getInputChannelName().c_str());
                    skipCallbacks = true;
                }
            }
            if (skipCallbacks) {
                mInputConsumer.sendFinishedSignal(seq, false);
            }
        }
    }
    

    1.8InputEventReceiver之dispatchInputEvent

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

    这个方法已经被子类WindowInputEventReceiver复写了

      @Override
       public void onInputEvent(InputEvent event, int displayId) {
                enqueueInputEvent(event, this, 0, true);
       }
    

    1.9onInputEvent

    内部调用的是enqueueInputEvent方法

     void enqueueInputEvent(InputEvent event,
                InputEventReceiver receiver, int flags, boolean processImmediately) {
            adjustInputEventForCompatibility(event);
            QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
            // 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.10doProcessInputEvents

    我们从上面的方法可以看到此时传递过来的processImmediately为true,我们看下
    doProcessInputEvents方法

    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);
                long eventTime = q.mEvent.getEventTimeNano();
                long oldestEventTime = eventTime;
                if (q.mEvent instanceof MotionEvent) {
                    MotionEvent me = (MotionEvent)q.mEvent;
                    if (me.getHistorySize() > 0) {
                        oldestEventTime = me.getHistoricalEventTimeNano(0);
                    }
                }
                mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);
                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);
            }
        }
    

    这里有一个while循环,主要的作用是将事件从队列中循环处理,直到队列中没有事件为止,我们看下deliverInputEvent方法的实现

    1.11deliverInputEvent

        private void deliverInputEvent(QueuedInputEvent q) {
            Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
                    q.mEvent.getSequenceNumber());
            if (mInputEventConsistencyVerifier != null) {
                mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
            }
            InputStage stage;
            if (q.shouldSendToSynthesizer()) {
                stage = mSyntheticInputStage;
            } else {
                stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
            }
            if (q.mEvent instanceof KeyEvent) {
                mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);
            }
           //上面是决定事件分发到那个InputStage中处理
            if (stage != null) {
                handleWindowFocusChanged();
                stage.deliver(q);//派发事件到InputStage中处理
            } else {
                finishInputEvent(q);
            }
        }
    

    InputStage是在setView方法中创建的,相当于一个单链表结构,也就是说,比如调用了mFirstPostImeInputStage.deliver(q)。那么SyntheticInputStage, ViewPostImeInputStage, NativePostImeInputStage, EarlyPostImeInputStage都将能够处理这个触摸事件。这里我们主要看看ViewPostImeInputStage是如何处理的。

    1.12ViewPostImeInputStage

           @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);
                    }
                }
            }
            @Override
            protected void onDeliverToNext(QueuedInputEvent q) {
                if (mUnbufferedInputDispatch
                        && q.mEvent instanceof MotionEvent
                        && ((MotionEvent)q.mEvent).isTouchEvent()
                        && isTerminalInputEvent(q.mEvent)) {
                    mUnbufferedInputDispatch = false;
                    scheduleConsumeBatchedInput();
                }
                super.onDeliverToNext(q);
            }
    

    1.13processPointerEvent

           private int processPointerEvent(QueuedInputEvent q) {
                final MotionEvent event = (MotionEvent)q.mEvent;
                mAttachInfo.mUnbufferedDispatchRequested = false;
                mAttachInfo.mHandlingPointerEvent = true;
                boolean handled = mView.dispatchPointerEvent(event);//调用view的方法
                maybeUpdatePointerIcon(event);
                maybeUpdateTooltip(event);
                mAttachInfo.mHandlingPointerEvent = false;
                if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
                    mUnbufferedInputDispatch = true;
                    if (mConsumeBatchedInputScheduled) {
                        scheduleConsumeBatchedInputImmediately();
                    }
                }
                return handled ? FINISH_HANDLED : FORWARD;
            }
    

    上面的view就是我们addView的时候赋值的,也就是decorView,这样事件也就传递给了view

    1.14dispatchPointerEvent

    我们知道DecorView的直接父类是FrameLayout,我们搜索下Decorview下没有dispatchPointerEvent,那么直接进入到View的dispatchPointerEvent方法

        public final boolean dispatchPointerEvent(MotionEvent event) {
            if (event.isTouchEvent()) {//是否是触摸事件
                return dispatchTouchEvent(event);
            } else {
                return dispatchGenericMotionEvent(event);
            }
        }
    

    由于子类DecorView复写了dispatchTouchEvent,进入到DecorView的dispatchTouchEvent方法

    1.15DecorView之dispatchTouchEvent

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

    我们知道Activity实现了Window.Callback接口,这里调用的是

    1.16Activity之disPatchTouchEvent

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

    1.17PhoneWindow之superDispatchTouchEvent

    @Override
    public boolean superDispatchTouchEvent(MotionEvent event) {
        return mDecor.superDispatchTouchEvent(event);//又回到了mDeCorView
    }
    

    1.18DecorView之superDispatchTouchEvent

        public boolean superDispatchTouchEvent(MotionEvent event) {
            return super.dispatchTouchEvent(event);//super值得是ViewGroup
        }
    

    1.19ViewGroup之dispatchTouchEvent

     // Check for interception.
                final boolean intercepted;
                if (actionMasked == MotionEvent.ACTION_DOWN
                        || mFirstTouchTarget != null) {
                    final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
                    if (!disallowIntercept) {
                        intercepted = onInterceptTouchEvent(ev);//是否继续分发,这个方法只有ViewGroup存在
                        ev.setAction(action); // restore action in case it was changed
                    } else {
                        intercepted = false;
                    }
                } else {
                    // There are no touch targets and this action is not an initial down
                    // so this view group continues to intercept touches.
                    intercepted = true;
                }
    

    这样整个事件就从view的顶端向下分发了,流向是DecorView--->ViewGroup---->View

    相关文章

      网友评论

        本文标题:Android事件分发流程(android9.0)

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