Android Event delivery mechanism

Source: Internet
Author: User

Experimental environment
    • OS X 10.9
    • Eclipse (ADT)
    • Android Source version: API level (Android 4.4)
Android Event composition

In Android, events mainly include tap, hold, drag, swipe, and so on, including click and double clicks, plus single-finger and multi-finger operations. All of this constitutes an event response in Android. In general, all events are based on the following three sections:

    • Press (Action_down)
    • Mobile (Action_move)
    • Lift Up (ACTION_UP)

All operation events must first be performed by pressing (Actiondown), after which all actions are taken as a precondition, and when the pressing operation is complete, then a move (actionmove) is then lifted (ACTION_UP), Or you can simply lift the button without moving when the operation is done. This series of actions can be controlled in Android.

We know that all of the event operations take place on the touchscreen, and on the screen we interact with a variety of view components (view), in Android, all views are inherited from view, and the layout of the view through various layout components (ViewGroup), ViewGroup also inherits from view. All UI controls such as button, TextView are inherited from view, and all layout controls such as Relativelayout, container controls such as ListView are inherited from ViewGroup. So, our event operations are mostly between view and ViewGroup, so what are the main ways to respond to these events in view and ViewGroup? Remember the following 3 methods, we can see by looking at the source code of view and ViewGroup:

View.java

Viewgroup.java

public boolean dispatchtouchevent (Motionevent event) Public boolean ontouchevent (Motionevent event) Public boolean Onintercepttouchevent (Motionevent event)

There are dispatchtouchevent and Ontouchevent methods in both view and ViewGroup, but there is a onintercepttouchevent method in ViewGroup, so what are these methods for? Don't worry, let's look at their return values first. The return values of these methods are all boolean type, why is the Boolean type, look at the title of this article, "Event delivery", the passing process is one after another, that to a point after the continued to continue to pass? Did you find out that the word "whether" would determine that these methods should use a Boolean as the return value. Yes, these methods all return TRUE or FALSE. In Android, all events are consumed from the beginning through to the completion event, and the return value of these methods determines whether an event continues to pass, is intercepted, or is consumed.

Next is the parameters of these methods, all of which accept a MotionEvent type of parameter, Motionevent inherited from InputEvent, to mark various action events. The previously mentioned Actiondown, Actionmove, and action_up are constants defined in Motinevent. We determine which type of event is received by motionevent the type of event passed in. By now, the return values and parameters of these three methods should all be understood, and the next step is to explain when these three methods deal with the events respectively.

    • dispatchTouchEventmethod is used for the distribution of events, all events in Android must be distributed through this method, and then decide whether to consume the current event itself or continue to distribute it to child control processing. Returns true to indicate that the distribution is not continued and the event is not consumed. Returns false to continue the distribution, if ViewGroup is distributed to onintercepttouchevent to determine whether to intercept the event.
    • onTouchEventThe method is used to handle the event, which returns true to indicate that the consumer handles the current event, returns false and does not process, and gives the child control to continue distribution.
    • onInterceptTouchEventIs ViewGroup in the method, no view, it is responsible for the interception of events, return true to intercept the current event, do not continue to distribute, to their own ontouchevent for processing. return false to Not intercept, continue to pass. This is a unique method for ViewGroup, because there may be sub-view in ViewGroup, and in Android view it is no longer possible to include child view (iOS can).

So far, the composition of events in Android and the role of event-handling methods you should be more clear, then we have a demo to actually experience the experiment.

Android Event handling

Start by creating a new project in Eclipse and create a new class Rtbutton inherit button to implement our tracking of button events.

Rtbutton.java

 public class Rtbutton extends Button {public Rtbutton (context context, AttributeSet Attrs) {Super (context, attrs);} @Overridepublic boolean dispatchtouchevent (Motionevent event) {switch (event.getaction ()) {case Motionevent.action_ DOWN:System.out.println ("Rtbutton---dispatchtouchevent---down"); Break;case Motionevent.action_move: System.out.println ("Rtbutton---dispatchtouchevent---MOVE"); Break;case MotionEvent.ACTION_UP:System.out.println ( "Rtbutton---dispatchtouchevent---up"); break;default:break;} Return Super.dispatchtouchevent (event);} @Overridepublic boolean ontouchevent (Motionevent event) {switch (event.getaction ()) {case Motionevent.action_down: System.out.println ("Rtbutton---ontouchevent---down"); Break;case MotionEvent.ACTION_MOVE:System.out.println (" Rtbutton---ontouchevent---MOVE ") break;case MotionEvent.ACTION_UP:System.out.println (" Rtbutton---ontouchevent---up "); break;default:break;} Return Super.ontouchevent (event);}} 

In Rtbutton I rewrote the dispatchtouchevent and Ontouchevent methods and obtained the motionevent of each event state, printing out the information in each state. The custom button Rtbutton is then placed directly under the root layout in the Activity_main.xml.

Activity_main.xml

<linearlayout xmlns:android= "http://schemas.android.com/apk/res/android"    xmlns:tools= "http// Schemas.android.com/tools "    android:id=" @+id/mylayout "    android:layout_width=" Match_parent "    android: layout_height= "Match_parent" >        <com.ryantang.eventdispatchdemo.rtbutton         android:id= "@+id/btn"        android:layout_width= "match_parent"        android:layout_height= "wrap_content"        android:text= "button"/ ></LinearLayout>

The next step in the activity is to set Ontouch and onclick listeners for Rtbutton to track the process of event delivery, and there is also a dispatchtouchevent method and a Ontouchevent method in the activity. We also rewrite them and print out the printed information.

Mainactivity.java

public class Mainactivity extends Activity {private Rtbutton button; @Overrideprotected void OnCreate (Bundle Savedinstancestate) {super.oncreate (savedinstancestate); Setcontentview (r.layout.activity_main); button = (RTButton ) This.findviewbyid (R.ID.BTN), Button.setontouchlistener (new Ontouchlistener () {@Overridepublic Boolean OnTouch (View V, motionevent event) {switch (event.getaction ()) {Case MotionEvent.ACTION_DOWN:System.out.println (" Rtbutton---onTouch---down ") break;case MotionEvent.ACTION_MOVE:System.out.println (" Rtbutton---onTouch---MOVE "); Break;case MotionEvent.ACTION_UP:System.out.println ("Rtbutton---onTouch---up"); break;default:break;} return false;}}); Button.setonclicklistener (New Onclicklistener () {@Overridepublic void OnClick (View v) {System.out.println ("Rtbutton Clicked! ");}}); @Overridepublic boolean dispatchtouchevent (Motionevent event) {switch (event.getaction ()) {case Motionevent.action_  DOWN:System.out.println ("Activity---dispatchtouchevent---down"); Break;case MotionevenT.action_move:system.out.println ("Activity---dispatchtouchevent---MOVE");  Break;case MotionEvent.ACTION_UP:System.out.println ("Activity---dispatchtouchevent---up"); Break;default:break;} Return Super.dispatchtouchevent (event);}  @Overridepublic boolean ontouchevent (Motionevent event) {switch (event.getaction ()) {case Motionevent.action_down:  System.out.println ("Activity---ontouchevent---down");  Break;case MotionEvent.ACTION_MOVE:System.out.println ("Activity---ontouchevent---MOVE");  Break;case MotionEvent.ACTION_UP:System.out.println ("Activity---ontouchevent---up"); Break;default:break;} Return Super.ontouchevent (event);}}

The code section has been completed, the next run the project, and click on the button to view the log output information, we can see the following results:

Through the log output can be seen, first performed the activity of the Dispatchtouchevent method for event distribution, in the MainActivity.java code line 55th, The return value of the Dispatchtouchevent method is Super.dispatchtouchevent (event), so call the parent class method, we enter Activity.java the source code to see the specific implementation.

Activity.java

/**     * Called to process touch screens events.  You can override this to     * intercept all touch screen events before they is dispatched to the     * window.  Be sure to the implementation for touch screens events     * That should be handled normally.     *      * @param ev the touch screen event.     *      * @return Boolean return True if this event is consumed.     */Public    Boolean dispatchtouchevent (motionevent ev) {        if (ev.getaction () = = Motionevent.action_down) {            onuserinteraction ();        }        if (GetWindow (). superdispatchtouchevent (EV)) {            return true;        }        return ontouchevent (EV);    }    

As can be seen from the source code, the Dispatchtouchevent method only handles the Actiondown event, as mentioned earlier, all events are pressed as the starting point, so, Android think when the Actiondown event is not executed, the subsequent events are meaningless , so here we first judge the Action_down event. If the event is true, the Onuserinteraction method is called, which can be overridden in the activity and called before the event is distributed. The return value of this method is void and does not affect the result of the event passing, and then the GetWindow (). superdispatchtouchevent (EV) execution results are determined to see its source code:

Activity.java

    /**     * 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);

Through the source annotation we can see that this is an abstract method for customizing the window, such as custom dialog to pass the touch event, and mentions that the developer does not need to implement or invoke the method, the system will complete, If we set the return value of the Dispatchtouchevent method to true in Mainactivity, then the execution result here is true, so the execution ontouchevent (EV) is not returned, and if this returns false, Then eventually the execution Ontouchevent method is returned, so the next thing to call is the Ontouchevent method. Don't worry, the log output information can be seen, action_down events from the activity was distributed to the Rtbutton, followed by the Ontouch and Ontouchevent methods, why first implement the Ontouch method? We go to Rtbutton in the dispatchtouchevent to see how the source code in view is handled.

View.java

/** * Pass the touch screen motion event 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 is handled by the view, false otherwise.            */Public Boolean dispatchtouchevent (Motionevent event) {if (minputeventconsistencyverifier! = null) {        Minputeventconsistencyverifier.ontouchevent (event, 0); } if (Onfiltertoucheventforsecurity (event)) {//noinspection simplifiableifstatement Listener            Info li = mlistenerinfo; if (Li! = null && Li.montouchlistener! = null && (mviewflags & enabled_mask) = = ENABLED && li            . Montouchlistener.ontouch (This, event)) {return true;            } if (Ontouchevent (event)) {return true; }} if (Minputeventconsistencyverifier! = null) {Minputeventconsistencyverifier.onunhandledevent (EVENT, 0);    } return false; }

Select the key code for analysis, you can see the code line 16th, here are several conditions, when a few conditions are satisfied when the method returns True, When the condition Li.montouchlistener is not empty, by looking in the source code, it is found that Montouchlistener is set in the following methods.

View.java

/**     * Register A callback to being invoked when a touch event was sent to this view.     * @param l the touch listener to attach to this view     *    /public void Setontouchlistener (Ontouchlistener l) {        ge Tlistenerinfo (). Montouchlistener = l;    }

This method is already familiar, is the MainActivity.java Ontouchlistener we set for Rtbutton in, conditions (mviewflags & enabled_mask) = = Enabled determines whether the current view is enabled or not, and the default is enable. Then there is the Li.mOnTouchListener.onTouch (this, event) condition, where the OnTouch method is called, and the invocation of this method is the MainActivity.java listener callback we set for Rtbutton in, if the method returns True, The entire condition is satisfied, Dispatchtouchevent returns True, indicating that the event will not continue to be distributed downward because it has been consumed by Ontouch.

If Ontouch returns false, then this judgment condition is not established, then the Ontouchevent (event) method is executed, and if the method returns True, the event is ontouchevent handled. The entire dispatchtouchevent returns TRUE. Here, we can answer the question of why we first implemented the Ontouch method. So far, the events of Actiondown have been distributed from activity to Rtbutton, then processed by Ontouch and ontouchevent, and eventually, The Actiondown incident was handed over to Rtbutton ontouchevent for processing.

The Actionup event occurs when our hands (which I use genymotion and then use the mouse to perform some actionmove actions) from the screen are lifted. As you can see from the previously output log confidence, the Actionup event is also distributed and processed from activity to Rtbutton, and finally, because we register the onclick event, the onclick event is called when the ontouchevent executes. So where is the onclick being invoked? Go back to View.java the source code to look for. Because ontouchevent in View.java the source code is relatively long, here is not posted out, interested can go into their own to study, through the source reading, we in the Actionup processing branch can see a performClick() method, from the source of this method can be seen to perform what operations.

View.java

/**     * Call this view ' s Onclicklistener, if it is defined.  Performs all normal     * actions associated with clicking:reporting accessibility event, playing     * a sound, etc.
   
    *     * @return True There was a assigned onclicklistener that were called, false     *         otherwise is returned.     */Public    Boolean PerformClick () {        sendaccessibilityevent (accessibilityevent.type_view_clicked);        Listenerinfo li = mlistenerinfo;        if (Li! = null && Li.monclicklistener! = null) {            playsoundeffect (soundeffectconstants.click);            Li.mOnClickListener.onClick (this);            return true;        }        return false;    }
   

In the IF branch you can see that the Li.mOnClickListener.onClick (this) is executed, and this code executes the OnClick method we implemented for Rtbutton, so so far, you can answer the previous " Where is the onclick being invoked? "The problem is that the onclick is executed in the ontouchevent, and the onclick is to be executed after the Ontouch.

By the end of the event, the click of the button, we have spied on the execution details with the source code, and if we modify the return value of each event control method What happens, take this issue and go to the next section of the discussion.

Android Event Blocker

From the previous section of the analysis, we know what types of events exist in Android, how events are delivered, and what processing methods are available in the source code. We can know that in Android, events are passed through a hierarchy, and an event pass corresponds to a complete hierarchical relationship, such as the Actiondown event analyzed in the previous section from activity to Rtbutton,actionup event. Combined with the source code analysis of each event processing method, you can also clearly see the process of the event.

As mentioned before, all the return values of the event handling methods are of type Boolean, now let's modify the return value, first from the activity, based on the previous log output, the first thing to do is the activity of the Dispatchtouchevent method, Now change the previous return value Super.dispatchtouchevent (event) to true, then recompile the run and click the button to see the following log output.

As you can see, the execution of the event to the Dispatchtouchevent method does not continue to distribute, which also verifies that the previous statement, return True, no longer continue to distribute, from the previously analyzed activity of the Dispatchtouchevent source code is also known , when True is returned, there is no way to execute the Ontouchevent method.

Next, restore the above modifications, let the event continue to distribute in activity, and then distribute to Rtbutton, modify the return value of the Rtbutton Dispatchtouchevent method to True, recompile the run and view the output log results.

As you can see from the results, the event has not been distributed further down the Rtbutton Dispatchtouchevent method. Then restore the above modifications, the Rtbutton Ontouchevent method return value is modified to true, let its consumption event, according to the previous analysis, the OnClick method is called in the Ontouchevent method, The event will not invoke the OnClick method after this is consumed, and compile and run, resulting in the following log output.

As with the results of the analysis, the OnClick method was not executed because the event was consumed in the Rtbutton ontouchevent method. Is the flowchart of the entire event pass.

So far, the event interception mechanism in Android has been analyzed. But here we only discuss the single-layout structure under the single-control situation, if it is nested layout, then what is the situation? Next we will be in the case of nested layout of the Android event delivery mechanism for further exploration and analysis.

Android Nested Layout event delivery

First, the new class Rtlayout inherits from LinearLayout, as well as the dispatchtouchevent and Ontouchevent methods, and also overrides the Onintercepttouchevent method, which was introduced at the beginning of the article , this method exists only in ViewGroup and its subclasses, and is used to control whether the event needs to be intercepted. This is not to be confused with dispatchtouchevent, which is to control the distribution of events and the latter to be executed first.

So, is the event passed to view first, or is it passed to ViewGroup first? We can draw conclusions from the following analysis. First, we need to make some modifications to the engineering code.

Rtlayout.java

public class Rtlayout extends LinearLayout {public Rtlayout (context context, AttributeSet Attrs) {Super (context, attrs);} @Overridepublic boolean dispatchtouchevent (Motionevent event) {switch (event.getaction ()) {case Motionevent.action_  DOWN:System.out.println ("Rtlayout---dispatchtouchevent---down");  Break;case MotionEvent.ACTION_MOVE:System.out.println ("Rtlayout---dispatchtouchevent---MOVE");  Break;case MotionEvent.ACTION_UP:System.out.println ("Rtlayout---dispatchtouchevent---up"); Break;default:break;} Return Super.dispatchtouchevent (event);} @Overridepublic boolean onintercepttouchevent (Motionevent event) {switch (event.getaction ()) {case Motionevent.action _down:system.out.println ("Rtlayout---onintercepttouchevent---down"); Break;case Motionevent.action_move: System.out.println ("Rtlayout---onintercepttouchevent---MOVE"); Break;case motionevent.action_up: System.out.println ("Rtlayout---onintercepttouchevent---up"); break;default:break;} Return Super.onintercepttouchevent (event);} @OVerridepublic boolean ontouchevent (Motionevent event) {switch (event.getaction ()) {case Motionevent.action_down: System.out.println ("Rtlayout---ontouchevent---down"); Break;case MotionEvent.ACTION_MOVE:System.out.println (" Rtlayout---ontouchevent---MOVE ") break;case MotionEvent.ACTION_UP:System.out.println (" Rtlayout---ontouchevent---up "); break;default:break;} Return Super.ontouchevent (event);}}

Also, in the layout file, add a parent layout for Rtbutton, indicating that the rtlayout is customized and the modified layout file is as follows.

Activity_main.xml

<linearlayout xmlns:android= "http://schemas.android.com/apk/res/android"    xmlns:tools= "http// Schemas.android.com/tools "    android:layout_width=" match_parent "    android:layout_height=" Match_parent " >    <com.ryantang.eventdispatchdemo.rtlayout        android:id= "@+id/mylayout"        android:layout_width= " Match_parent "        android:layout_height=" match_parent ">        <com.ryantang.eventdispatchdemo.rtbutton            android:id= "@+id/btn"            android:layout_width= "match_parent"            android:layout_height= "Wrap_content"            android:text= "button"/>    </com.ryantang.eventdispatchdemo.RTLayout></LinearLayout>

Finally, we also set the Ontouch and onclick events for rtlayout in the activity, adding the following code in Mainactivity.

Mainactivity.java

Rtlayout.setontouchlistener (New Ontouchlistener () {@Overridepublic Boolean onTouch (View V, motionevent event) {switch ( Event.getaction ()) {case MotionEvent.ACTION_DOWN:System.out.println ("Rtlayout---onTouch---"); break;case MotionEvent.ACTION_MOVE:System.out.println ("Rtlayout---onTouch---MOVE"); Break;case motionevent.action_up: System.out.println ("Rtlayout---onTouch---up"); break;default:break;} return false;}}); Rtlayout.setonclicklistener (New Onclicklistener () {@Overridepublic void OnClick (View v) {System.out.println (" Rtlayout clicked! ");});

After the code has been modified, compile and run the project, again, click the button to view the results of the log output as follows:

From the log output we can see, after nesting the rtlayout, the order of events passed into Activity->rtlayout->rtbutton, which also answered the previous question, In Android, event delivery is passed from ViewGroup to view, not in reverse.

From the output of the third line can be seen, the implementation of the Rtlayout Onintercepttouchevent method, the role of the method is to determine whether to intercept the event, we go to ViewGroup source code to see the implementation of the method.

Viewgroup.java

public boolean onintercepttouchevent (motionevent ev) {        return false;    }

The implementation of this method is simple and returns only one false. Then this method is where to be called, through the log output analysis that it is executed after the execution of Rtlayout dispatchtouchevent, then we go into the dispatchtouchevent source code inside to see. Because of the long source code, I will be the key part of the interception to explain.

Viewgroup.java

            Check for interception.            Final Boolean intercepted;            if (actionmasked = = Motionevent.action_down                    | | Mfirsttouchtarget! = NULL) {                final Boolean disallowintercept = (MG Roupflags & flag_disallow_intercept)! = 0;                if (!disallowintercept) {                    intercepted = onintercepttouchevent (EV);                    Ev.setaction (action); Restore action in case it is changed                } else {                    intercepted = false;                }            } else {                //there is no t Ouch targets and this action are not a initial down                /So this view group continues to intercept touches.                intercepted = true;            }

From this section of the code you can see that the return value is assigned to intercepted after the Onintercepttouchevent call, which controls whether the event is to be distributed to its child controls, so it acts as an intercept, If Onintercepttouchevent returns false then the current event is intercepted if True is returned. We will now modify the method return value in Rtlayout to TRUE and recompile the run, then click on the button to see the output as follows.

Can see, we clearly click on the button, but the output results show Rtlayout Click event is executed, and then through the output analysis, compared to the last output results, found that the output of this time completely no rtbutton information, yes, Because the Onintercepttouchevent method returns True, the event is intercepted here, so he will not continue to distribute to Rtbutton, but instead to his own ontouchevent method of execution, for granted, The last thing to do is a Rtlayout click event.

Summarize

Above we have analyzed the Android event transmission mechanism, and during the process of the event transmission, the system source code is explored. Through the analysis of event passing and processing in the case of single layout and nested layout, we summarize the following:

    • Event delivery in Android is routed from top to bottom, with event handling from activity to ViewGroup to view.
    • The event delivery method includes,, dispatchTouchEvent onTouchEvent onInterceptTouchEvent , where the first two are both view and ViewGroup, and the last one is only the ViewGroup method. These three methods are responsible for event distribution, event handling, and event interception, respectively.
    • The Ontouch event is executed prior to the onclick event, Ontouch is called in the event distribution method Dispatchtouchevent, and the onclick is called in the event-handling method Ontouchevent. Ontouchevent to be called after the Dispatchtouchevent method.

Android Event delivery mechanism

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.