Event distribution mechanism in Android--viewgroup event distribution

Source: Internet
Author: User
Tags gety

Overview

The event distribution mechanism in Android is the distribution and processing of events between view and ViewGroup. The interior of ViewGroup contains many view, and ViewGroup inherits from view, so ViewGroup itself is also a view. The event can be viewgroup to its child view and processed by the child view, and ViewGroup itself can handle the event. The following is a detailed analysis of the viewgroup time distribution processing.

motionevent

When the finger touches the screen, the resulting sequence of events is comprised of the following three types of events.
1. action_down: Finger Press the screen
2. action_move: the finger moves on the screen
3. action_up: finger lifted from the screen
For example, a simple screen touch action triggers a series of touch events: ACTION_DOWN->ACTION_MOVE->...->ACTION_MOVE->ACTION_UP
For this event distribution mechanism in Android, this event refers to Motionevent. The distribution of the view's events is also a distribution operation to Motionevent. You can use GETRAWX and Getrawy to get the horizontal ordinate of events relative to the upper-left corner of the screen. Gets the horizontal ordinate of the event relative to the upper-left corner of the current view through Getx () and Gety ().

three important methods

public boolean dispatchtouchevent (motionevent ev)

This is a way to distribute the event. If an event is passed to the current view, the current view must call the method. The return type for Dispatchtouchevent is Boolean, and the return result indicates whether the event is consumed, and if true, indicates that the view has been consumed and will not continue to pass down.
  
public boolean onintercepttouchevent (motionevent ev)

This method exists in the ViewGroup class, and there is no such method for the view class. Indicates whether to intercept an event, ViewGroup if an event is successfully intercepted, then the event is not passed down. For the same event sequence, if the current view successfully intercepts the event, the method will not be called again for subsequent series of events. The returned result indicates whether to intercept the current event and return false by default. Because a view is already at its lowest level, it does not have child controls, so there is no such method.
  
public boolean ontouchevent (Motionevent event)

This method is called by Dispatchtouchevent to handle the event and is used to indicate whether the current event is consumed by the returned result. If the current event is not consumed, the current view will not receive the event again for the same sequence of events.
  

View Event Distribution Flowchart

For the distribution of events, here's a flowchart to look at the entire distribution process.

ViewGroup Event Distribution Source Analysis

According to the flowchart above, we will analyze the whole process of ViewGroup event distribution in detail now.
A series of events generated by swiping the finger on the touchscreen, and when the activity receives these events, the event is distributed by invoking the Dispatchtouchevent method of the activity. Here's a look at the Dispatchtouchevent method of activity.

publicbooleandispatchTouchEvent(MotionEvent ev) {    if (ev.getAction() == MotionEvent.ACTION_DOWN) {        onUserInteraction();    }    if (getWindow().superDispatchTouchEvent(ev)) {        returntrue;    }    return onTouchEvent(ev);}

by GetWindow (). superdispatchtouchevent (EV) This method can be seen, this time the activity will also be the event to the window processing. Window It is an abstract class, its implementation is only a phonewindow, that is to say, the activity will be the event to Phonewindow in the Superdispatchtouchevent method. Now trace it in and look at this superdispatchtouchevent code.

publicsuperDispatchTouchEventevent) {    return mDecor.superDispatchTouchEvent(event);}

The Mdecor inside it is a decorview,decorview it is a top view of activity. It is an inner class of Phonewindow, inherited from Framelayout. So at this time the incident was handed over to Decorview's Superdispatchtouchevent method to deal with. Here's a look at the Superdispatchtouchevent method.

publicsuperDispatchTouchEventevent) {    return super.dispatchTouchEvent(event);}

At this point it is clear to see Decorview it invokes the Dispatchtouchevent method of the parent class. In the above mentioned Decorview it inherits the Framelayout, and this framelayout inherits from ViewGroup. So at this time the incident began to be handed over to viewgroup for processing. Let's start with a detailed look at this viewgroup dispatchtouchevent method. Because the Dispatchtouchevent code is longer, here is a partial code to explain.

// Handle an initial down.if (actionMasked == MotionEvent.ACTION_DOWN) {    //statewhen starting a new touch gesture.    orfor the previous gesture    orstate change.    cancelAndClearTouchTargets(ev);    resetTouchState();}

As can be seen from the above code, the received events are judged in dispatchtouchevent, and when the Action_down event is received, the target and state of the event distribution is emptied. The Resettouchstate method is then executed to reset the touch state. Here's a look at these two methods.
  1. Cancelandcleartouchtargets (EV)

PrivateTouchtarget Mfirsttouchtarget;Private void cancelandcleartouchtargets(motioneventEvent) {if(Mfirsttouchtarget! =NULL) {Boolean syntheticevent =false;if(Event==NULL) {FinalLongnow = Systemclock.uptimemillis ();Event= Motionevent.obtain (now, now, Motionevent.action_cancel,0.0F0.0F0);Event. SetSource (Inputdevice.source_touchscreen); Syntheticevent =true; } for(Touchtarget target = mfirsttouchtarget; Target! =NULL;            target = Target.next) {resetcancelnextupflag (target.child); Dispatchtransformedtouchevent (Event,true, Target.child, target.pointeridbits); } cleartouchtargets ();if(syntheticevent) {Event. Recycle (); }    }}

Here first introduce mfirsttouchtarget, it is Touchtarget object, Touchtarget is an inner class of viewgroup, Touchtarget use the linked list data structure to store view. The main function in this method is to empty the Mfirsttouchtarget list and set Mfirsttouchtarget to null.
  2. Resettouchstate ()

privatevoidresetTouchState() {    clearTouchTargets();    resetCancelNextUpFlag(this);    mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;    mNestedScrollAxes = SCROLL_AXIS_NONE;}

Here is a description of the flag_disallow_intercept tag, which is a flag that prohibits ViewGroup interception events, which can be set by the Requestdisallowintercepttouchevent method. When this tag is set, ViewGroup will not be able to intercept events other than Action_down. As you can see in the code above, when the event is Action_down, the flag_disallow_intercept tag is reset.
Then go back to the Dispatchtouchevent method again to see its source code.

//Check forInterception.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 actioninch  CaseIt was changed}Else{intercepted =false; }}Else{//There isNoTouch targets and  ThisAction is  notAn initial down//So ThisView Group continues to intercept touches. intercepted =true;}

This code is primarily a viewgroup of whether an event needs interception. The following is a description of whether Mfirsttouchtarget is null. When an event is not intercepted, the child element of ViewGroup successfully handles the event, and Mfirsttouchtarget is assigned a value and points to its child elements. That means this time mfirsttouchtarget!=null. However, once an event is intercepted, Mfirsttouchtarget is not assigned, and Mfirsttouchtarget is null.
As you can see in the code above, according to actionmasked==motionevent.action_down| | Mfirsttouchtarget!=null These two cases to determine whether the event needs to be intercepted. For Actionmasked==motionevent.action_down This condition is well understood, for the two cases of mfirsttouchtarget!=null have been explained above. Then for an event sequence, when the event is Motionevent.action_down, the flag_disallow_intercept is reset, which means that!disallowintercept must be true, The Onintercepttouchevent method is bound to be executed, and for the Onintercepttouchevent method, the default return is False, so when a ViewGroup intercept event is required, You must override the Onintercepttouchevent method and return True. One thing to note here is that for an event sequence, once an event in the sequence is successfully intercepted, the Onintercepttouchevent method is executed, which means that the Onintercepttouchevent return value is true, Then the event follows a series of events for the condition actionmasked==motionevent.action_down| | Mfirsttouchtarget!=null is bound to be false, then the sequence of events that are left at this time will be intercepted and the Onintercepttouchevent method will not be executed. So here's a conclusion:for an event sequence, when one of the events is successfully intercepted, the remaining column events are intercepted and the Onintercepttouchevent method is not executed again
Here's a look at how the ViewGroup does not intercept events.

Final intChildrencount = Mchildrencount;if(Newtouchtarget = =NULL&& Childrencount! =0) {Final floatx = Ev.getx (Actionindex);Final floaty = ev.gety (Actionindex);//Find a child that can receive the event.    //Scan children from front to back.    Finalarraylist<view> preorderedlist = Buildorderedchildlist ();Final BooleanCustomorder = Preorderedlist = =NULL&& ischildrendrawingorderenabled ();FinalView[] 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); }if(Preorderedlist! =NULL) Preorderedlist.clear ();}

While this code is long, the logic here is not very complex. First get the number of child view and ViewGroup in the current viewgroup. The elements in the ViewGroup are then traversed incrementally. When you get to a child element in ViewGroup, determine whether the element can receive touch events. If a child element is able to receive a touch event, and the touch coordinate is within the visual range of the child element, it continues to execute downward. Otherwise, continue. There are two criteria for measuring whether a child element can receive touch events: If the child element is playing the animation and the coordinates of the Click event are within the area of the child element.
Once the child view receives a touch event, it then begins to call the Dispatchtransformedtouchevent method to distribute the event. For the Dispatchtransformedtouchevent method code is more, now only focus on the following five lines of code. As can be seen from the following 5 lines of code, this time the dispatchtouchevent of the child view is called, that is, at this point ViewGroup has completed the entire process of event distribution.

ifnull) {    handled = super.dispatchTouchEvent(eventelse {    handled = child.dispatchTouchEvent(event);}

When the dispatchtouchevent of a child element returns True, that is, the child view succeeds in handling the event. The Mfirsttouchtarget is then assigned by the Addtouchtarget method.
If Dispatchtouchevent returns false, or if the current viewgroup has no child elements, then the following code is called.

ifnull) {    // No touch targets so treat this as an ordinary view.    null,            TouchTarget.ALL_POINTER_IDS);}

Call the Dispatchtransformedtouchevent method here and set the child parameter to NULL. That is, the Super.dispatchtouchevent (event) method is executed. Since ViewGroup inherits from view, it is time to handle the event yourself.
Here for the ViewGroup event distribution has been finished, in this way down, it is not difficult to find that for dispatchtouchevent there is a Boolean type return value. For this return value, when True indicates that the current event has been successfully processed, and if it returns false, it is generally because the event handler Ontouchevent returns False, and the change is referred to its parent control for processing. It will eventually be dealt with by the Ontouchevent method of the activity.

Summary

Here, from the macroscopic point of view of this viewgroup to the distribution of the event, when ViewGroup received an event sequence, the first to determine whether to intercept the event, if the event is intercepted, the event is handled by itself. If you do not intercept this event, the event is sent to the sub view. If ViewGroup does not have a child view, or if the child view fails to handle the event, the event is referred to the ViewGroup, and if the viewgroup fails to handle the event, the event is eventually referred to the activity for processing.

Event distribution mechanism in Android--viewgroup event distribution

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.