Overview
Android event delivery mechanism is also an important piece of the Android system, there are many types of events, here mainly discusses the TouchEvent event in the framework layer of the transfer processing mechanism. Because for app developers, understanding the event passing mechanism of the framework layer is almost there.
Think about the entire event distribution process with questions.
1, why should there be an event distribution process?
When the screen of the Android device receives the action of the touch, the screen driver passes the pressure signal (including pressure, pressure, etc.) to the bottom of the system, then the operating system passes a series of processing, and then passes the touch event one layer at a time, and the final event is passed to the object that generated the event. The system iterates through each view object and calculates which view the touch points are in. For example A and B two view, is the brother View,aview generated touch events, is not distributed to B above.
2, how to view the sequence of events?
In Android, a single event is basically useless, and only one sequence of events makes sense. A sequence of events is normally defined as down, MOVE (0 or more), Up/cancel. The sequence of events starts with the down event, with 0 or more move events in the middle, ending with an up event or a cancel event.
The down event, as the beginning of the sequence, has a very important responsibility, that is, to find the recipient of the sequence of events, how to understand it? During the pass of the down event, the framework needs to determine the recipient of the sequence of events based on the return value of the View event handling method (Ontouchevent). If a view's Ontouchevent event returns True when handling the down event, it is willing to accept and process the sequence of events.
3. How does the Android framework layer handle the event distribution process?
Once the touch event has reached the framework layer, it is first passed to the activity, and the activity delegates the event to its internal window object for distribution processing, and the Window object delegates its internal decorview for event distribution processing. As we all know, Decorview is the root node of the entire view tree, so the complexity of the entire event delivery process is the complexity of the event's distribution and delivery in view tree species. The Android View Framework provides 3 key operational concepts for events.
1, the distribution mechanism of the event, Dispatchtouchevent. It is primarily the mechanism by which the parent distributes events to child based on the location of the touch event and whether or not the child is willing to handle the status of that series of events.
2, the interception mechanism of the event, Onintercepttouchevent. The main thing is that the parent intercepts the event to prevent further transmission to the child's mechanism, based on its internal state or the state of the child.
3, the handling mechanism of the event, Ontouchevent. It is primarily the recipient of the sequence of events (which can be a view or viewgroup) that handles the event and passes the mechanism of processing results to its parent.
4, the above three mechanism, how to pass the processing result to its caller?
In Java, there are many ways to pass the results of a calculation, and here is a method that applies to the method of synchronous invocation, which returns the value. Each mechanism uses a Boolean type as its return value, so what does each return value of each mechanism mean?
1, the distribution mechanism of the event, Dispatchtouchevent.
true-the event is successfully processed by the view tree with the node as the root node, at which point the event is processed and the event is no longer returned up to the view's parent node (the node to which the event was distributed).
false-the view tree with the node as the root node does not have a view (including the view) that successfully handles this event, so the event is returned to the parent node of view (the node to which the event was distributed).
2, the interception mechanism of the event, Onintercepttouchevent. The main thing is that the parent intercepts the event to prevent further transmission to the child's mechanism, based on its internal state or the state of the child.
true-current viewgroup ( because there is no method in view, and no child view does not need an interception mechanism ) want the event to no longer be passed to its child, but want to handle it on its own.
false-the current viewgroup is not ready to intercept the event, and the event is distributed gracefully to its child.
3, the handling mechanism of the event, Ontouchevent. It is primarily the recipient of the sequence of events (which can be a view or viewgroup) that handles the event and passes the mechanism of processing results to its parent.
true-Indicates that the view successfully processed the event and the processing result is notified up to its parent.
false-Indicates that the view did not successfully process the event, then its parent has a chance to handle the event (the parent is marked as the event sequence recipient, and the parent's ontouchevent returns true on the Down event).
Source Code Analysis
Source code based on SDK 23
View:1, Dispatchtouchevent:
/** distributes the event to the target object, because this is the view object, and the default does not contain child, so here he will distribute the event to himself */
public boolean dispatchtouchevent (Motionevent event);
Source:
Do not give an interested reader to execute the Lookup SDK
Pseudo code:
Public Booleandispatchtouchevent (Motionevent event) {Booleanresult =false; //If there is an event listener, let the listener handle the event first. if(Montouchlistener.ontouch (event)) {//If the listener successfully processed the event, the processing result is set to true. result =true; } //If there is no listener, call its own Ontouchevent method to handle the event. if(!resutlt &&ontouchevent (event)) { //If the event is handled successfully by its own ontouchevent, the processing result is set to true. result =true; } returnresult;}
Viewgroup:1, Onintercepttouchevent
/** the default implementation is to return false or to not intercept any events by default */
public boolean onintercepttouchevent (Motionevent ev);
2, Dispatchtouchevent
/** distribution of events to child or itself based on internal interception status */
public boolean dispatchtouchevent (Motionevent ev);
Source:
Do not give an interested reader to execute the Lookup SDK
Pseudo code:
Public Booleandispatchtouchevent (motionevent ev) {if(Action_down Event | |no event handling object) { if(Allow intercept event, this flag bit is called by child Requestdisallowintercepttouchevent<span style= "font-family: Microsoft Jas; font-size:14px;" > Settings </span>) { //The result of the query interception mechanism, based on the result, to determine if interception is requiredintercepted =onintercepttouchevent (EV); } Else { //no interception is allowed, so do not interceptintercepted =false; } } Else { //not down, and there are processing objects that allow interception, interrupt event deliveryintercepted =true; } if(Do not cancel &&do not intercept) { if(Action_down) {//looking for the object that receives the sequence of events, other events do not need to compute the event object, just imagine sliding a listview, when the finger slides out of the ListView range, the ListView still responds to subsequent events. for(Traverse all Childview) {if(touch point not inside Childview) {Continue; } if{childview.dispatchtouchevent (Event)} Saves the view that handles the event, and subsequent events are passed directly to the view, not recalculated; } } } if(no event handling object) {//The current View tree does not find the appropriate child processing object, the event to self-processing, view.dispatchtouchevent () is to distribute the event to their own Super. Dispatchtouchevent (event); } Else { //Pass to childchildview.dispatchtouchevent (event); } } Else if(intercept) {//To intercept an event , to deal with it, View.dispatchtouchevent () to distribute the event to himself. Super. Dispatchtouchevent (event); } returnprocessing results;}
3, Requestdisallowintercepttouchevent
/** Dry Parent Event distribution mechanism, notify parent, whether to intercept subsequent events, if set to True,parent will not intercept the event, regardless of state. Set to False,parent to go through the normal interception process */
public void Requestdisallowintercepttouchevent (Boolean disallowintercept);
Source:
Do not give an interested reader to execute the Lookup SDK
Pseudo code:
Public void requestdisallowintercepttouchevent (boolean disallowintercept) { if (already the state to be set) {// already in this state, assuming our parent is also this state return; } set the state; // Pass to Parent if (with parent container) { Sets the interception state of the parent container;} }
Do it yourself.
As we all know, if the ListView is nested inside the ScrollView, then the ListView is not sliding, as shown in the effect:
So in fact this is the typical event conflict problem, that is, the original should be used by the ListView to swipe up and down the event, was ScrollView intercepted. Causes the ListView to not slide properly.
Let's take a look at the source code for ScrollView:
Onintercepttouchevent Pseudo-code:
Public Booleanonintercepttouchevent (motionevent ev) {/** This method determines whether we want to intercept the event. * If it returns True, Ontouchevent is called and we start to do the actual scroll operation. */ /** Most loop state: The user is in a state of drag and is moving his finger, * we want to intercept this event*/ Final intAction =ev.getaction (); if(action = = motionevent.action_move) &&(misbeingdragged)) { return true; } //Other Operations ......................}
So the normal up and down drag, ScrollView will intercept.
So let's improve on that when we slide the ScrollView in the non-ListView area, ScrollView slides while we slide the ListView, the ListView Slides, and the effect looks like this:
Here are the workarounds:
Since ScrollView will intercept the event, we do not want ScrollView to intercept the event when we slide the ListView, where we inherit the ListView, and in Ontouchevent, request ScrollView not intercept the event.
Some of the code is as follows:
@Override Public Booleanontouchevent (motionevent ev) {Super. ontouchevent (EV); Switch(Ev.getaction ()) { CaseMotionEvent.ACTION_DOWN:getParent (). Requestdisallowintercepttouchevent (true); Break; CaseMotionevent.action_move: Break; CaseMotionEvent.ACTION_UP:getParent (). Requestdisallowintercepttouchevent (false); Break; default: Break; } return true;}
This will be a good solution to the problem of event conflict.
Another way is to overwrite the Onintercepttouchevent method of the parent to modify the state of the event interception.
An exploration of the event distribution mechanism of Android view