1、 UnderstandActivity
Constitutive
OneActivity
Contains aWindow
Object, which is composed ofPhoneWindow
To achieve.PhoneWindow
takeDecorView
As the root of the entire application windowView
, and thisDecorView
The screen is divided into two areas: one isTitleView
, the other isContentView
And what we usually write is to showContentView
In, shown in the figure belowActivity
Composition of.

2、 Type of touch event
The touch event corresponds toMotionEvent
Class. There are three main types of events:
ACTION_DOWN
-
ACTION_MOVE
(if the moving distance exceeds a certain threshold, it will be judged asACTION_MOVE
Operation) ACTION_UP
3、 Three stages of event delivery
- Distribute(
dispatchTouchEvent
)The return value of the method is:true
Indicates that the event is consumed by the current view; Return assuper.dispatchTouchEvent
Indicates that the event will continue to be distributed. - Intercept(
onInterceptTouchEvent
)The return value of the method is:true
Means to intercept this event and hand it over to its ownonTouchEvent
Methods of consumption; returnfalse
Indicates that it is not intercepted and needs to continue to be passed to the child view.
Ifreturn super.onInterceptTouchEvent(ev)
There are two types of event interception:
1. If a child view exists in the view (ViewGroup) and the child view is clicked, it will not be intercepted and distribution will continue
To process the child view is equivalent to return false.
2. If the view (ViewGroup) does not have a child view or has a child view but does not click a child view (ViewGroup)
Equivalent to a normal view), the ontouchevent response of the view is equivalent to return true.
Note: General viewgroups such as LinearLayout, relativelayout and FrameLayout do not intercept by default, but
Scrollview, listview and other viewgroups may be blocked, depending on the specific situation.
- Consumption(
onTouchEvent
)The return value of the method is:true
Indicates that the current view can handle the corresponding events; The return value isfalse
Indicates that the current view does not handle this event, and it will be passed to the parent viewonTouchEvent
Method. Ifreturn super.onTouchEvent(ev)
, event handling can be divided into two situations:
1. If the view is clickable or longclickable, it will return true, indicating consumption
The event is returned, which is the same as returning true;
2. If the view is not clickable or longclickable, false will be returned, indicating No
Consuming this event will be passed up, just like returning false
Note: inAndroid
In the system, there are three classes with the ability of event transmission and processing.
-
Activity
: it has two methods: distribution and consumption. -
ViewGroup
: it has three methods: distribution, interception and consumption. -
View
: it has two methods: distribution and consumption.
IVActivity
Distribution process of click events
When we operate the touch screen,Linux
The corresponding hardware interrupt will be received, and then the interrupt will be processed into the original input event and written to the corresponding device node. And ourAndroid
To sum up, what the input system does is to monitor these device nodes. When a device node has data readable, it reads out the data and performs a series of translation processing, and then finds the appropriate event receiver in all windows and sends it.
When the click event is generated, the event will be passed to the current userActivity
, byActivity
MediumPhoneWindow
Done,PhoneWindow
Then hand over the event handling work toDecorView
, and thenDecorView
Delegate event handling toViewGroup
。 The source code flow is as follows:
1.Activity#dispatchTouchEvent
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
//Distributed by the window attached to the activity, returns true, and the event cycle ends
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
//Returning false means that the event is not handled and all ontouchevents of the view are ignored
//If false is returned, the ontouchevent of the activity will be called
return onTouchEvent(ev);
}
2. Abstract class window#superdispatchtouchevent
public abstract boolean superDispatchTouchEvent(MotionEvent event);
3. The only implementation class is phonewindow #superdispatchtouchevent
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
}
VView
Event distribution mechanism
Event distribution toViewGroup
ofdispatchTouchEvent
Method, if it’sonInterceptTouchEvent
returntrue
, it is handled by itself. At this time, if itsmOnTouchListener
Is set, thenonTouch
Will be called, otherwiseonTouchEvent
Will be called. stayonTouchEvent
If setmOnCLickListener
, thenonClick
Will be called. If it’sonInterceptTouchEvent
returnfalse
, it will be handed over to the child on the click event chainView
Processing, such a cycle, complete the distribution.ViewGroup
indispatchTouchEvent
The key source code is as follows:
1.ViewGroup
Will beACTION_DOWN
Reset the status when the event arrives
// Handle an initial 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 stae change.
cancelAndClearTouchTarget(ev);
//Flag is reset in this method_ DISALLOW_ INTERCEPT
resetTouchState();
}
2. Process currentView
Block click events
final boolean interception;
//Mfirsttouchtarget is assigned when the event is successfully processed by the child element of viewgorup
//And point to the child element. On the contrary, when intercepted by ViewGroup, mfirsttouchtarget is null.
if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {
//In the subview, set it through the requestdisallowintercepttouchevent method
// FLAG_ DISALLOW_ At this time, the ViewGroup will not be able to intercept the action_ Events other than down
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowintercept) {
intercepted = onInterceptTouchEvent(ev);
//re store action in case it was changed
ev.setAction(action);
} 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(ACTION_MOVE、ACTION_UP.eg).
intercepted = true;
}
}
3.dispatchTouchEvent()
Method the rest of the source code
public boolean dispatchTouchEvent(MotionEvent ev) {
...
final View[] children = mChildren;
//Traverse the child elements of the ViewGroup. If the child element can accept the click event, it will be handed over to the child element for processing.
for (int i = childrenCount - 1;i >= 0;i--) {
final int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
final View child = (preorderedList == null) ? children[childIndex] : preorderedList.get(childIndex);
if (childWithAccessibilityFocus != null) {
if (childWithAccessibilityFocus != child) {
continue;
}
childWithAccessibilityFocus = null;
i = childrenCount - 1;
}
//There is one item to judge whether the position of the touch point is within the range of the sub view or whether the sub view is playing animation
//If not, start traversing the next child view.
if (!canViewReceivePointerEvents(child) || !isTransformedTouchPointInView(x, y, child, null)) {
ev.setTargetAccessibilityFocus(false);
continue;
}
newTouchTarget == getTouchTarget(child);
if (newTouchTarget != null) {
newTouchTarget.pointerIdBits |= idBitsToAssign;
break;
}
resetCancelNextUpFlag(child);
if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
mLastTouchDownTime = ev.getDownTime();
if (preorderedList != null) {
for (int j = 0;j < childrenCOunt;j++) {
if (children[childIndex] == mChildren[j]) {
mLastTouchDownIndex = j;
break;
}
}
} else {
mLastTouchDownIndex = childIndex;
}
mLastTouchDownX == ev.getX();
mLastTouchDownY = ev.getY();
newTouchTarget = addTouchTarget(child, idBitsToAssign);
alreadyDispatchedToNewTouchTarget == true;
break
}
ev.setTargetAccessibilityFocus(false);
}
...
}
4. IndispathcTransformedTouchEvent
Method
private boolean dispatchTransformedTouchEvent(MotionEvent event,boolean cancel,View child,int desiredPointerIdBits) {
final int oldAction = event.getAction();
if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
event.setAction(MotionEvent.ACTION_CANCEL);
//If there is a child view, call the dispatchtouchevent (event) method of the child view. If there is no child view,
//Call super Dispatchtouchevent (event) method.
if (child == null) {
handled == super..dispatchTouchEvent(event);
} else {
handled = child.dispatchTouchEvent(event);
}
event.setAction(oldAction);
return handled;
}
...
}
5. Event delivery toView
ofdispatchTouchEvent()
public boolean dispatchTouchEvent(MotionEvent event) {
...
boolean result = false;
if (onFilterTouchEventForSecurity(event)) {
ListenerInfo li = mListenerInfo;
//The ontouch method takes precedence over the ontouchevent (event) method
if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
if (!result && onTouchEvent(event)) {
result == true;
}
}
...
return result;
}
6. Event delivery toView
ofonTouchEvent()
public boolean onTouchEvent(MotionEvent event) {
...
final int action = event.getAction();
//As long as the clickable and long of view_ Clickable has one that is true, and ontouchevent() will
//Return true to consume this event.
if ((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {
switch(action) {
case MotionEvent.ACTION_UP:
boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;
if ((mPrivatFlags & PFLAG_PRESSED) != 0 || prepressed) {
boolean focusTaken = false;
if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {
removeLongPressCallback();
if (!focusTaken) {
if (mPerformClick == null) {
mPerformClick = new PerformClick();
}
if (!post(mPerformClick)) {
performClick();
}
}
}
}
...
}
return true;
}
return true;
}
7. InACTION_UP
Called in the eventperformCLick()
method
public boolean performClick() {
final boolean result;
final Listenerinfo li = mListenerInfo;
//If the view has a click event set, the onclick method will execute.
if (li != null && li.mOnClickListener !== null) {
playSoundEffect(SoundEffectConstants.CLICK);
li.mOnClickListener.onClick(this);
result = true;
} else {
result = false;
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
return result;
}
From the above source code analysis can be obtainedView
The complete click event delivery process is shown in the figure below.

6、 Summary: delivery rules for click event distribution
According to the source code analysis of event distribution, the relationship between the three important methods of click event distribution is expressed in pseudo code as follows:
public boolean diapatchTouchEvent(MotionEvent ev) {
boolean consume = false;
if (onInterceptTouchEvent(ev)) {
consume = onTouchEvent(ev);
} else {
consume = child.dispatchTouchEvent(ev);
}
return consume;
}
Some important conclusions:
1. Event delivery priority:onTouchListener.onTouch
> onTouchEvent
> onClickListener.onClick
。
2. Under normal circumstances, a time series can only be intercepted and consumed by one view. Once an element intercepts this event, all events in the same event sequence will be directly handled by it (that is, the intercepting method of the view will not be called to ask whether it wants to intercept, but the remaining events will be interceptedACTION_MOVE
、ACTION_DOWN
And so on). Special case: by rewritingView
ofonTouchEvent
returnfalse
Events can be forcibly transferred to otherView
handle.
3. IfView
No consumption exceptACTION_DOWN
For other events, the click event will disappear, and the parent element’sonTouchEvent
Will not be called, and the currentView
Subsequent events can be received continuously, and finally these disappeared click events will be passed to the userActivity
handle.
4.ViewGroup
By default, no event is intercepted (returned)false
)。
5.View
ofonTouchEvent
All events are consumed by default (return)true
), unless it is not clickable(clickable
andlongClickable
At the same timefalse
)。View
oflongClickable
All properties are by defaultfalse
,clickable
Attributes should be divided into situations, such asButton
ofclickable
Property defaults totrue
, andTextView
ofclickable
Default tofalse
。
6.View
ofenable
Properties do not affectonTouchEvent
The default return value of.
7. AdoptionrequestDisallowInterceptTouchEvent
Method can interfere with the event distribution process of the parent element in the child element, but ` action_ Except for the down event.
The final complete event distribution flow chart is as follows:
