"Android" event delivery process

1. What is the event delivery?
Android event delivery refers to a series of user operation event actions generated screen (pressing, sliding, lifting) the process is transferred from the outer to the inner layer.

2, how to understand the outer to the inner layer?
Activity -> Window ----> ViewGroup ---- > View

3, must understand the basic
3.1 must first know the object passed is an object MotionEvent class. This class defines a constant operation, such as "press" public static final int ACTION_DOWN = 0 and the like.
3.2 second to know three important ways:
boolean dispatchTouchEvent (MotionEvent ev) distribution event ev
boolean onInterceptTouchEvent (MotionEvent ev) is blocking the event ev
boolean onTouchEvent (MotionEvent ev) whether the event ev consume
about 3.3 regularly to view the event set listening methods
view.setOnTouchListener (...) touch event listener
view.setOnClickListener (...) click event listeners

4, the specific process event delivery of
4.1 generates events:
finger touch screen to produce a first MotionEvent Down event, as the finger sliding produce more MotionEvent Move event, finally raised his finger to produce a MotionEvent Up events
4.2 event in the Activity:
Activity in there dispatchTouchEvent (), onTouchEvent () 2 methods.

 /**
     * Called to process touch screen events.  You can override this to
     * intercept all touch screen events before they are dispatched to the
     * window.  Be sure to call this implementation for touch screen events
     * that should be handled normally.
     *
     * @param ev The touch screen event.
     *
     * @return boolean Return true if this event was consumed.
     */
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            onUserInteraction();
        }
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        return onTouchEvent(ev);
    }
     /**
     * Called when a touch screen event was not handled by any of the views
     * under it.  This is most useful to process touch events that happen
     * outside of your window bounds, where there is no view to receive it.
     *
     * @param event The touch screen event being processed.
     *
     * @return Return true if you have consumed the event, false if you haven't.
     * The default implementation always returns false.
     */
    public boolean onTouchEvent(MotionEvent event) {
        if (mWindow.shouldCloseOnTouch(this, event)) {
            finish();
            return true;
        }

        return false;
    }

dispatchTouchEvent event go passed getWindow (). superDispatchTouchEvent (ev) do judge, if the return is true, the direct end. Activity onTouchEvent if the trigger is false () method.
That in Activity in (). SuperDispatchTouchEvent (ev) method passes the event to the Window by getWindow.
4.3 In the event of the Window:
. GetWindow () superDispatchTouchEvent (EV) call superDispatchTouchEvent inside the Window () method.

 /**
     * Used by custom windows, such as Dialog, to pass the touch screen event
     * further down the view hierarchy. Application developers should
     * not need to implement or call this.
     *
     */
    public abstract boolean superDispatchTouchEvent(MotionEvent event);

This is an abstract method. The only specific logic in the derived class PhoneWidow Window:

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

The event did not do the task in the window in the process, passing directly through mDecor.superDispatchTouchEvent (event) to the DecorView. DecorView is the top view of an object is defined in the PhoneWindow. It is a class that inherits from FrameLayout of ViewGroup.

// This is the top-level view of the window, containing the window decor.
    private DecorView mDecor;

4.4 In the event ViewGroup in:
events to DecorView of superDispatchTouchEvent () method

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

Call super.dispatchTouchEvent (event), this super is actually ViewGroup.
There dispatchTouchEvent (), onInterceptTouchEvent (), onTouchEvent () 3 of methods on the ViewGroup.
As the source is too long, which also contains a lot of control unit, in order to analyze the process of stickers out directly is not intuitive, I do not want excessive length of their own to see more impressive! Direct summarize:
(1) event MotionEvent passed for event distribution to dispatchTouchEvent (EV)
(2) within the distribution method calls if onInterceptTouchEvent (ev) interpretation of the event interception (returned for false does not intercept, true representation interception default is false.) .
(3) onInterceptTouchEvent (ev) returns true, explain to intercept events, ev will be forwarded to this viewGroup process.
(4) If viewGroup set OnTouchListener, onTouch () is called, onTouch () returns false viewGroup of onTouchEvent will be called. OnTouch () Returns true viewGroup of onTouchEvent will be blocked.
(5) onInterceptTouchEvent (ev) returns false, does not block the event, you will pass the event to sub-View (view or viewGroup) of dispatchTouchEvent (ev) process. If the child view is ViewGroup continue from (1) to start the cycle.

4.4 In the event of View:
There dispatchTouchEvent (), onTouchEvent () 2 methods on the View. No onInterceptTouchEvent ()
is similar to ViewGroup process, after all ViewGroup inherited from View. ViewGroup did not rewrite onTouchEvent, so ViewGroup in onTouchEvent () method is the View of the method.
(1) Event MotionEvent passed to dispatchTouchEvent (ev) for event distribution
(2) If the view is set OnTouchListener, onTouch () is called, onTouch () returns false view of onTouchEvent will be called. OnTouch () Returns true view of onTouchEvent will be blocked.

5, setOnTouchListener () \ setOnClickListener ( ) \ onTouchEvent () calls the relationship:
The following is a view of dispatchTouchEvent () Source

/**
     * Pass the touch screen motion event down to the target view, or this
     * view if it is the target.
     *
     * @param event The motion event to be dispatched.
     * @return True if the event was handled by the view, false otherwise.
     */
    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
            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }

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

Wherein determining the mOnTouchListener! = Null && mOnTouchListener.onTouch (this , event) condition, then return the results in accordance with determination whether to invoke onTouchEvent (event). Verified OnTouchListener priority calls, and control onTouchEvent () call.
In view of onTouchEvent () method

 public boolean onTouchEvent(MotionEvent event) {
        ...代码省略...
        if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {
            switch (action) {
                case MotionEvent.ACTION_UP:
                    ...代码省略...
                            if (!focusTaken) {
                                if (mPerformClick == null) {
                                    mPerformClick = new PerformClick();
                                }
                                if (!post(mPerformClick)) {
                                    performClickInternal();
                                }
                            }
                            ...代码省略...
                        }
         ...代码省略...

performClickInternal () method will be transferred performClick (), posted PerformClick () Code

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) {
            playSoundEffect(SoundEffectConstants.CLICK);
            li.mOnClickListener.onClick(this);
            result = true;
        } else {
            result = false;
        }

        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);

        notifyEnterOrExitForAutoFillIfNeeded(true);

        return result;
    }

Here triggered li.mOnClickListener.onClick (this). Description onClick click event is called indirectly in onTouchEvent in.

6, the case to the upper layer processing
sub-view can not handle events when, onTouchEvent returns false, the event will be given to onTouchEvent call the parent view. If you can not handle the event in turn passed up. Until Activity. That is, getWindow (). SuperDispatchTouchEvent (ev) returns false. Activity will be called the onTouchEvent () method.

Released six original articles · won praise 14 · views 20000 +

Guess you like

Origin blog.csdn.net/u010823943/article/details/105176685