Android View System (v) the event distribution mechanism for resolving view from source code

Source: Internet
Author: User

Related articles
Android View System (i) Views coordinate system
Android View System (ii) six ways to implement view swipe
Android View System (iii) property animation
Android View System (iv) parsing from source code scroller

Preface

Three years ago wrote the event distribution mechanism article but not very good, so write again, about the event distribution mechanism of the article has a lot, but I hope this is the most concise, the most understandable article.

1. How to handle click events level of view

We know that the structure of the view is a tree structure, the view can be placed in the ViewGroup, the ViewGroup can also be placed in another viewgroup, so that layers of nesting is composed of the view hierarchy.

What is Click event Distribution

When we click on the screen, a touch event is generated, and the event is encapsulated into a class: Motionevent. And when this motionevent is generated, then the system will pass this motionevent to the view hierarchy, motionevent the process of passing through the view hierarchy is click event Distribution.

important ways to click event Distribution

There are three important ways to click events:

    • Dispatchtouchevent (motionevent ev): Used for distribution of events
    • Onintercepttouchevent (motionevent ev): Used for event interception, called in Dispatchtouchevent (), it is important to note that view does not provide this method
    • Ontouchevent (motionevent ev): Used to handle click events, called in the Dispatchtouchevent () method

To understand the relationship of these three methods, let's take a look at some of the source code of the ViewGroup Dispatchtouchevent () method:

@Override public boolean dispatchtouchevent (Motionevent ev) {...Omittedif(actionmasked = = Motionevent.action_down | | Mfirsttouchtarget! = NULL) {Final Boolean disallowintercept = (Mgroupflags & flag_disallow_intercept)! =0;if(!disallowintercept)                    {intercepted = Onintercepttouchevent (EV); Ev.setaction (action); Restore actioninchCase it is changed}Else{intercepted = false; }            }Else{//There is no touch targets and this action is a initial down/so this view group                continues to intercept touches.            intercepted = true; }...OmittedreturnHandled }

It is obvious that the Onintercepttouchevent () method is called in the Dispatchtouchevent () method to determine whether to intercept the event, and to take a look at the Onintercepttouchevent () method:

publicbooleanonInterceptTouchEvent(MotionEvent ev) {        returnfalse;    }

The Onintercepttouchevent () method returns false by default, does not intercept, and then looks at the following parts of the Dispatchtouchevent () method:

  Public Boolean dispatchtouchevent(Motionevent ev) { ... OmittedFinalView[] children = Mchildren; for(inti = Childrencount-1; I >=0; i--) {Final intChildindex = Customorder? Getchilddrawingorder (Childrencount, i): i;FinalView Child = (Preorderedlist = =NULL)                                    ? Children[childindex]: Preorderedlist.get (Childindex);//If There is a view this has accessibility focus we want it                            //To get the event first and if not handled we'll perform a                            //Normal dispatch. We may do a double iteration it is                            //safer given the timeframe.                            if(Childwithaccessibilityfocus! =NULL) {if(Childwithaccessibilityfocus! = child) {Continue; } Childwithaccessibilityfocus =NULL; i = Childrencount-1; }if(!canviewreceivepointerevents (child) | |!istransformedtouchpointinview (x, Y, child,NULL) {Ev.settargetaccessibilityfocus (false);Continue; } Newtouchtarget = Gettouchtarget (child);if(Newtouchtarget! =NULL) {//already receiving touch within its bounds.                                //Give it the new pointer in addition to the ones it is handling.Newtouchtarget.pointeridbits |= idbitstoassign; Break; } resetcancelnextupflag (child);if(Dispatchtransformedtouchevent (EV,false, child, Idbitstoassign)) {//child wants to receive touch within its bounds.Mlasttouchdowntime = Ev.getdowntime ();if(Preorderedlist! =NULL) {//Childindex points into presorted list, find original index                                     for(intj =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; }//The accessibility focus didn ' t handle the event, so clear                            //The flag and do a normal dispatch to all children.Ev.settargetaccessibilityfocus (false); } ... Omitted

We see the For loop, first traversing the child elements of the ViewGroup to determine if the child element can receive a click event, and if the child element is able to receive it, the child element is processed. Next look at what is implemented in the Dispatchtransformedtouchevent () method:

 PrivateBooleandispatchtransformedtouchevent(motioneventEvent, Boolean cancel, View child,intDesiredpointeridbits) {Final Boolean handled;//Canceling motions is a special case. We don ' t need to perform any transformations        //or filtering. The important part was the action, not the contents.FinalintOldaction =Event. Getaction ();if(Cancel | | oldaction = = motionevent.action_cancel) {Event. Setaction (Motionevent.action_cancel);if(Child = =NULL) {handled = Super.dispatchtouchevent (Event); }Else{handled = Child.dispatchtouchevent (Event); }Event. Setaction (Oldaction);returnHandled }  ... Omitted

If there is a child view, the Dispatchtouchevent (event) method of the child view is called. If ViewGroup does not have a child view to call Super.dispatchtouchevent (event), ViewGroup is inheriting the view, let's take a look at the dispatchtouchevent of the View (event):

 public boolean dispatchtouchevent (Motionevent event) { ...         Omit Boolean result = false; if  (Onfiltertoucheventforsecurity (event))            {//noinspection simplifiableifstatement listenerinfo li = mlistenerinfo; if  (Li! = null && Li.montouchlistener! = null && (mviewflags & enabled_mask) = = ENABLE            D && Li.mOnTouchListener.onTouch (this, event)) {result = true;             } if  (!result && ontouchevent (event)) {result = true; }}  ...     Omit return  result; }

We see that if Ontouchlistener is not null and the Ontouch () method returns True, it means that the event is consumed and the Ontouchevent (event) is not executed, or ontouchevent (event) is executed. Take a look at some of the source code for the Ontouchevent () method:

  Public Boolean ontouchevent(Motionevent event) {      ... OmittedFinal intAction = Event.getaction ();if((viewflags & clickable) = = Clickable | |                (ViewFlags & long_clickable) = = long_clickable) | | (ViewFlags & context_clickable) = = context_clickable) {Switch(action) { CaseMOTIONEVENT.ACTION_UP:Booleanprepressed = (Mprivateflags & pflag_prepressed)! =0;if((Mprivateflags & pflag_pressed)! =0|| prepressed) {//Take focus if we don't have an it already and we should in                        //Touch mode.                        BooleanFocustaken =false;if(!mhasperformedlongpress &&!mignorenextupevent) {//This was a tap, so remove the Longpress checkRemovelongpresscallback ();//Only perform take click on actions if we were in the pressed state                            if(!focustaken) {//Use a Runnable and post this rather than calling                                //PerformClick directly. This lets other visual state                                //Of the view update before click Actions Start.                                if(Mperformclick = =NULL) {Mperformclick =NewPerformClick (); }if(!post (Mperformclick))                                {PerformClick (); }                            }                        }       ... Omittedreturn true; }return false; }

The above can be seen as long as the view's clickable and long_clickable one is true, then Ontouchevent will return true to consume this event. Clickable and long_clickable represent view can be clicked and long-clicked, can be set by the view's setclickable and Setlongclickable methods, It can also be set by View's Setonclicklistenter and Setonlongclicklistener, and they will automatically set the view to clickable and long_clickable.
The PerformClick () method is then called in the Action_up event:

 public  boolean  performclick  () {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);    return  result; }

If the view is set to click event Onclicklistener, then its onclick () method will be executed.

2. Click Delivery Rules for event distribution

See here we can know the Click event distribution of these three important methods of the relationship, with pseudo-code to simply Express is:

publicbooleandispatchTouchEventboolean result=falseif(onInterceptTouchEvent(ev)){       result=super.onTouchEvent(ev);  }else{       return result;
Click on Event-by-top delivery rules

When a click event is generated, the activity will handle the ViewGroup passed to the window and then passed to the top layer, typically only the ViewGroup onintercepttouchevent () method is considered in the event pass. As a general rule we do not rewrite the Dispatchtouchevent () method.
For Root viewgroup, click the Dispatchtouchevent () method that the event is passed first to it, and if the ViewGroup's Onintercepttouchevent () method returns True, it means that it is intercepting the event. This event will be given to its ontouchevent () method, and if the Onintercepttouchevent () method returns false, it means that it does not intercept the event, then it is given the dispatchtouchevent () of its child elements to handle, So again and again. If the View,view is passed to the lowest level without a child view, the view's Dispatchtouchevent () method is called, and the Ontouchevent () method of the view is typically called in the end.

A real-world example is that our application has produced a major bug, and this bug is first reported to the technical Director:

Technical director (top floor ViewGroup) → Technical Manager (middle ViewGroup) → engineer (bottom view)
Technical director does not intercept, the bug assigned to the technical manager, the technical manager does not intercept the bug assigned to the engineer, the engineer has no subordinates to deal with.
The event is passed up and down by the return value rule: true, intercept, do not continue to pass down, false, do not intercept, continue to pass down.

Click on the event from the bottom of the pass rule

The Click event passes to the lowest view, and if his ontouchevent () method returns True, the event is consumed and processed by the lowest view, and if False indicates that the view is not processed, it is passed to the parent view's ontouchevent () processing, If the parent view's ontouchevent () still returns false, it continues to pass to the parent view processing of the changed parent view, and so on.

Returning to our example of reality, the engineer found the bug too Difficult (Ontouchevent () return false), he can only be handled by the superior technical manager, if the technical manager is also uncertain (Ontouchevent () return false), then the bug to the technical director , technical Director The bug is easy to solve (Ontouchevent () returns True).

The event is passed down by the return value rule as: true, processed, not continued upward, false, not processed, continues to pass up.

other issues when clicking Event delivery
    • The above source we see: If we set the Ontouchlistener and the Ontouch () method returns True, the Ontouchevent () method will not be called, otherwise the Ontouchevent () method will be called. Visible Ontouchlistener have higher priority than ontouchevent (). In the Ontouchevent () method, if Onclicklistener is currently set, its onclick () method is executed.
    • The view's Ontouchevent () method returns true by default unless it is not clickable, that is, clickable and long_clickable are false.

Android View System (v) the event distribution mechanism for resolving view from source code

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.