Book attached to the text: event distribution analysis – copy jingdong home page two linkage
structure
The event
An event is a MotionEvent object.
ACTION_DOWN: Event starts, mainly handles the event distribution, when the distribution is finished, the mFirstTouchTarget is assigned (handles the event’s child View list).
ACTION_MOVE: The move event will be triggered multiple times. For a View, if there is no down, there must be no move. But the ViewGroup, if it’s not down, it’s going to have a second move event. Because it is triggered multiple times, the source code must be viewed multiple times
ACTION_UP: The event is over
ACTION_CANCEL: When an event is moved, it is assigned as cancel. The second Move can be intercepted by the upper layer
View and ViewGroup structure
1. The ViewGroup extends the View. So methods that are not implemented in the ViewGroup call the View method. ViewGroup does not implement event handling, so it calls the View’s event handling dispatchTouchEvent
2. From the layout perspective, the father of View must be ViewGroup. So the ViewGroup sends events layer by layer to the View. A ViewGroup might send events to its own subviews, or call its own (extends View) dispatchTouchEvent to handle them.
Event handling: View.java –> dispatchTouchEvent Event distribution: viewGroup. Java –> dispatchTouchEvent
The incident
There is only one event, but more than one person wants to handle it. If the object being handled is not the one we want to give, then there is an event conflict.
Resolution: There are two ways to resolve event conflicts: internal interception and external interception. Child View to handle, called internal interception. His father ViewGroup to handle, call external interception.
The whole process
Event handling – View
First of all, events are handled on the View onClick and onTouch. OnTouch is executed first and onClick is executed later. When onTouch returns false, onClick executes. When onTouch returns true, onClick does not execute. Indicates that the event onTouch was consumed. The reason that onClick does not return a value is that the event is already consumed when onClick is executed.
The source code
Java dispatchTouchEvent ()
To look down
The core code
So much for the core code of event handling
1. The && processing logic in Java is like this,if(a && b && c)
If a=false, b is not executed. If b=false, do not execute c
ListenerInfo li = mListenerInfo; What is this?
Point into the getListenerInfo ()
So mListenerInfo in the first couple of conditions is the new OnTouchListener in the setOnTouchListener, so as long as setOnTouchListener is implemented then the first couple of conditions are true, So li will be executed. MOnTouchListener. The onTouch (this event))
Point into li. MOnTouchListener. The onTouch (this event)) found a interface,
So it’s going to do a custom onTouch
The return value true and false in the custom onTouch will affect the return value of view.DispatchTouchEvent (). So onTouch returns true to indicate that the event was consumed, and false= no consumption
So the return value in the custom onTouch is true, result = true; if (! Result && onTouchEvent(event)) if the first condition is not true, then onTouchEvent(event) will not be executed, so onClick() will not be executed in the onTouchEvent(Event) ACTION_UP method
OnTouchEvent (event) onTouchEvent() has down, up, and so on. Where onClick is in the Up event.
There’s a performClick in the up event of onTouchEvent
Point in
PerformClick () method
1. Handle button sound
2. Handle the onClick
3.result = true;
That would be the end of the matter
Event distribution – ViewGroup
Event distribution is dispatchTouchEvent () in the ViewGroup, where the source code is the focus.
To streamline the source code
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
/ /... omit
if (onFilterTouchEventForSecurity(ev)) {
/ /... omit
if (actionMasked == MotionEvent.ACTION_DOWN) {
/** Clear the last event cache */
cancelAndClearTouchTargets(ev);
resetTouchState();
}
/** Intercept judgment */
final boolean intercepted;
if(actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget ! =null) { final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) ! =0;
if(! disallowIntercept) { intercepted = onInterceptTouchEvent(ev); ev.setAction(action);// restore action in case it was changed
} else {
intercepted = false; }}else {
intercepted = true;
}
/ /... omit
** Event distribution */
if(! canceled && ! intercepted) {if (actionMasked == MotionEvent.ACTION_DOWN
|| (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
|| actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
/ /... omit
// Number of subviews
final int childrenCount = mChildrenCount;
if (newTouchTarget == null&& childrenCount ! =0) {
/** Traverse the child View*/
final View[] children = mChildren;
for (int i = childrenCount - 1; i >= 0; i--) {
/ /... omit
/** Determine whether the subview needs to distribute */
if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
/ /... omit
newTouchTarget = addTouchTarget(child, idBitsToAssign);
alreadyDispatchedToNewTouchTarget = true;
break;
}
}
}
}
}
/** Specific execution distribution */
// Whether to intercept
if (mFirstTouchTarget == null) {
handled = dispatchTransformedTouchEvent(ev, canceled, null,
TouchTarget.ALL_POINTER_IDS);
} else {
TouchTarget predecessor = null;
TouchTarget target = mFirstTouchTarget;
while(target ! =null) {
final TouchTarget next = target.next;
if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
handled = true;
} else {
final boolean cancelChild = resetCancelNextUpFlag(target.child)
|| intercepted;
if (dispatchTransformedTouchEvent(ev, cancelChild,
target.child, target.pointerIdBits)) {
handled = true;
}
if (cancelChild) {
target = next;
continue; } } predecessor = target; target = next; }}}return handled;
}
Copy the code
Event distribution structure – Down event!
1. Clear the cache
Skip some accessibility and other code
2. Intercept judgment
1. If it is ACTION_DOWN or mFirstTouchTarget! = null (it must be null at the beginning, before traversing the subview) 2. Child View is not set an intercept (shots requestDisallowInterceptTouchEvent () 3. This is the onInterceptTouchEvent () method
You need to override onInterceptTouchEvent () to return true for intercepting
3. Interception judgment – Interception (OnInterceptTouchEvent () returns true
)
Skip the middle section of code. Go straight to the final distribution execution process
DispatchTransformedTouchEvent ()
This method is the handling method of event distribution, important!! When child is null
When child is empty, call “Handled” = Super.DispatchTouchEvent (transformedEvent); That is, the dispatchTouchEvent in the call’s own (Viewgroup) extends (inherited) View
The return value: Handled is whether the thing was handled
4. Intercept judgment – When not intercepting (OnInterceptTouchEvent () returns false
)
- When you don’t intercept, you go
if (! canceled && ! intercepted)
这
- Down Indicates the normal flow of the event
3. If there is a child View, insert it into an ArrayListArrayList (in XML order, textView/ImagView… List(0) =ImagView, List(1) = textView
- For traverses the child View to determine whether to distribute
Important!! If (dispatchTransformedTouchEvent (ev, false, child, idBitsToAssign)) the method to judge whether son consumption, without spending for the next, To consume, addTouchTarget to mFirstTouchTarget and break out of the loop.
3.1 points into dispatchTransformedTouchEvent method
Points into dispatchTransformedTouchEvent method, when the child is not null, the call will be handled = child. DispatchTouchEvent (transformedEvent); When the child is a View, it will call the View’s dispatchTouchEvent to handle the event, and when the child is a ViewGroup, it will call the ViewGroup’s dispatchTouchEvent to (recursively) distribute the event, and then iterate over the son’s son… One layer at a time.
- Determine the distribution of
Next = null mFirstTouchTarget = target; ! =null alreadyDispatchedToNewTouchTarget = true
- If a for iterates through, there is no subclass that handles the event, which is all of the subviews
Before dispatchTransformedTouchEvent () is false, then go to intercept code
- If you have a child View that you want to handle, addTouchTarget and then break; Out of the for loop, go mFirstTouchTarget! = NULL to distribute the event
- In the distribution case
while (target ! = null)
This while loop usually only goes once (single touch, multi-touch multiple times).
Step 5: While the for loop is looking for the child View to handle, the event has already been sent to the View, so the tag “Handled” =true returns
Event distribution — Move events!
The Down event determines which View consumes the event, but the Move event still starts with the top ViewGroup
1. Do not clear the cache
- Because mFirstTouchTarget! = null so it still goes through the intercept or not process
- If there is no interception, then if (! canceled && ! intercepted) here will still go. When the subview is down, the distribution event is finished, so the subview will not distribute the event
- After skipping the distribution event code, it’s the last step, because mFirstTouchTarget! =null, so else
- DispatchTransformedTouchEvent () distribute events, distributed to save the child before the View
Event conflict resolution
Event conflicts can only be handled when moving!!
The resolution of event conflicts is divided into internal interception (child View handling) and external interception (parent container handling).
Internal intercept
Internal interception, child View of dispatchTouchEvent through getParent () requestDisallowInterceptTouchEvent whether to set up the father shall have the right to intercept
getParent().requestDisallowInterceptTouchEvent(); This method is the sword of the above code. A child View can set the parent container to prevent it from intercepting.
But that’s not enough, because ViewGroup DOWN clears the cache, so there’s no way to set the child View, so you have to deal with the parent DOWN, right
External intercept
External intercepting is controlled by setting onInterceptTouchEvent of the parent container, whether the parent container intercepts or not