Android analysis view event distribution mechanism from source code

Source: Internet
Author: User

has been to view the event distribution mechanism is not very clear, in the project development also encountered, in the online also found some problem-solving methods, but its principle is not very understanding, now resigned to have time, today write a view of the event distribution, combined with the Android source code together to learn, if not speaking, Go to the point of learning to improve together.

Create a new Android project with only one activity, with a button, we set the button to Setonclicklistener (), Setontouchlistener (), and look at the result via log:

Btnclick.setonclicklistener (New Onclicklistener () {@Overridepublic void OnClick (View v) {log.i ("Com.example.demo", " button click ");});

Touch Event for Button:

<span style= "FONT-SIZE:18PX;" >btnclick.setontouchlistener (New Ontouchlistener () {@Overridepublic Boolean onTouch (View V, motionevent event) { LOG.I ("Com.example.demo", "button Touch" +event.getaction ()); return false;}}); </span>

LOG:


You can see that Ontouch takes precedence over the onclick, and Ontouch executes several times, because the Ontouch event consists of the three parts of Dwon,move,up, so Ontouch executes several times, So why is the order of execution first ontouch after the onclick?

Observing the onclick and Ontouch will find that the Ontouch () method has a return value, the default is to return false, and if we instead return true, what will be different, click Print Log to see:

Com.example.demo (3280): Button Touch 0com.example.demo (3280): Button Touch 2com.example.demo (3280): Button touch 2com.example.demo (3280): Button Touch 2com.example.demo (3280): Button Touch 2com.example.demo (3280): Button Touch 1

Using the log result to find that the onclick event is not executed, we can understand that when Ontouch returns True, the button event is consumed, which is equivalent to blocking the view event.Will not continue to pass down, so the onclick event is not executed,

The first thing to know is that if you touch any of the controls on the interface, you will be sure to invoke the Dispatchtouchevent method of the control. This method takes precedence over Ontouch and the onclick first executes, when we go to click the button, will go to call in button class Dispatchtouchevent method, then we go to button source code to find this method, button the source code is very few, does not have this method, Button source code is as follows:


Although there is no such method, but we see the button inherited TextView, then to TextView to find, but in TextView did not find the Dispatchtouchevent () method, it can only find TextView of the parent class, and TextView's parent class is the view object, that in the view source code to find Dispatchtouchevent () method to see its execution logic:


Let's first translate the description of this method:

@param event The motion event to be dispatched, incident Action Events Dispatch

@return True if the event is handled by the view, False otherwise. Returns true if the event is processed, otherwise it returns false,

Now look at the code in the Dispatchtouchevent () method, see the source has a method, not all the code to understand,

The focus in the Dispatchtouchevent () method is to see

if (Montouchlistener! = null && (mviewflags & enabled_mask) = = ENABLED &&                    Montouchlistener.ontouch (this, event)) {                return true;            } if (Ontouchevent (event)) {                return true;            }


First look at the first if statement,
When is the Montouchlistener variable initialized? We traced it and found it initialized at
<pre name= "code" class= "java" > public void Setontouchlistener (Ontouchlistener l) {        montouchlistener = l;    }

So this is when we are Setontouchlistener, Montouchlistener can be assigned, so this variable is not NULL.

The second condition (mviewflags & enabled_mask) = = ENABLED is to determine whether the currently clicked control is enable and the button is enable by default, so this condition is constant true

The third condition of the IF condition Montouchlistener.ontouch (this, event) we click on the OnTouch () method to find:

Public interface Ontouchlistener {        /**         * called if a touch event is dispatched to a view. This allows listeners to         * Get a chance to respond before the target view.         *         * @param v The View the touch event has a been dispatched to.         * @param event The Motionevent object containing full information about         * The        event.         * @return True If the listener has consumed the event, false otherwise.         *        /Boolean OnTouch (View V, motionevent event);    }

found that it is an interface in the method, for the callback, in fact, we set the return value of the Ontouchlistener method,


And we return true, so the IF condition evaluates to True, then the following statement is not executed.

if (Ontouchevent (event)) {                return true;            }
Let's look at the logic of the Ontouchevent method: The source code is as follows:

 public boolean ontouchevent (Motionevent event) {final int viewflags = mviewflags; if ((ViewFlags & enabled_mask) = = DISABLED) {if (event.getaction () = = Motionevent.action_up && (mP                Rivateflags & PRESSED)! = 0) {mprivateflags &= ~pressed;            Refreshdrawablestate (); }//A disabled view is clickable still consumes the touch/events, it just doesn ' t respond t            o them.                    Return (((viewflags & clickable) = = Clickable | |        (ViewFlags & long_clickable) = = long_clickable));            if (mtouchdelegate! = null) {if (Mtouchdelegate.ontouchevent (event)) {return true;                }} if (((viewflags & clickable) = = Clickable | | (ViewFlags & long_clickable) = = long_clickable) {switch (event.getaction ()) {case Motione Vent. Action_up:booleAn prepressed = (Mprivateflags & prepressed)! = 0; if ((Mprivateflags & PRESSED)! = 0 | | prepressed) {//Take focus if we don ' t has it already a                        nd we should in//touch mode.                        Boolean focustaken = false; if (isfocusable () && isfocusableintouchmode () &&!isfocused ()) {Focustaken = R                        Equestfocus ();                            } if (prepressed) {//The button is being released before we actually  showed it as pressed.                            Make it show the pressed//state now (before scheduling the click) to ensure                            The user sees it.                            Mprivateflags |= PRESSED;                       Refreshdrawablestate ();        } if (!mhasperformedlongpress) {                    This was a tap, so remove the Longpress check Removelongpresscallback (); Only perform take click Actions if we were in the pressed state I                                F (!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 = new PerformClick ();                                    } if (!post (Mperformclick)) {                                PerformClick ();                            }}} if (munsetpressedstate = = null) { Munsetpressedstate = new Unsetpressedstate ();                                    } if (prepressed) {postdelayed (munsetpressedstate,                        Viewconfiguration.getpressedstateduration ());                            } else if (!post (munsetpressedstate)) {//If the post failed, unpress right now                        Munsetpressedstate.run ();                    } removetapcallback ();                } break;                    Case MotionEvent.ACTION_DOWN:mHasPerformedLongPress = false;                    if (Performbuttonactionontouchdown (event)) {break;                    }//Walk up the hierarchy to determine if we ' re inside a scrolling container.                    Boolean isinscrollingcontainer = Isinscrollingcontainer ();              For views inside a scrolling container, delay the pressed feedback for      A short period in case the is a scroll.                        if (isinscrollingcontainer) {mprivateflags |= prepressed;                        if (Mpendingcheckfortap = = null) {Mpendingcheckfortap = new Checkfortap ();                    } postdelayed (Mpendingcheckfortap, Viewconfiguration.gettaptimeout ());                        } else {//not inside a scrolling container, so show the feedback right away                        Mprivateflags |= PRESSED;                        Refreshdrawablestate ();                    Checkforlongclick (0);                } break;                    Case MotionEvent.ACTION_CANCEL:mPrivateFlags &= ~pressed;                    Refreshdrawablestate ();                    Removetapcallback ();                Break case MotionEvent.ACTION_MOVE:final int x = (int) event.geTX ();                    Final int y = (int) event.gety ();                        Be lenient about moving outside of buttons if (!pointinview (x, Y, Mtouchslop)) {                        Outside button Removetapcallback ();                            if ((Mprivateflags & PRESSED)! = 0) {//Remove any future long Press/tap checks                            Removelongpresscallback ();                            Need to switch from pressed to not pressed mprivateflags &= ~pressed;                        Refreshdrawablestate ();            }} break;        } return true;    } return false; }
We found that the source of this method is too much, but the Ontouchevent () method In fact, we just look at the code in case motionevent.action_up, because we touch the last thing to do here,after all the judgment, the code will come here:

if (!post (Mperformclick)) {                                    performclick ();      }
Then execute the PerformClick () method, the code inside the PerformClick method:

public boolean PerformClick () {        sendaccessibilityevent (accessibilityevent.type_view_clicked);        if (Monclicklistener! = null) {            playsoundeffect (soundeffectconstants.click);            Monclicklistener.onclick (this);            return true;        }        return false;    }
First look at the IF condition, monclicklistener this variable is set when we click, so it is not NULL, then we look at an important method, is also a callback method,

Monclicklistener.onclick (this);

This is the setting of the view click event, through the source we should now understand the first time we set the onclick and Ontouch event delivery order,

Summarize:

1: If the View object Setontouchlistener method returns True, the View object will not execute the Click event, and if Settouchlistener is set to False,view the Click event will be executed.

There is also an important knowledge that we know that the touch event consists of Dwon,move,up, as follows:

Btnclick.setontouchlistener (New Ontouchlistener () {@Overridepublic Boolean onTouch (View V, motionevent event) {if ( Event.getaction () ==motionevent.action_down) {log.i ("Com.example.demo", "Action_down"); return false;} else if (event.getaction () ==motionevent.action_move) {log.i ("Com.example.demo", "Action_move");} ELSE{LOG.I ("Com.example.demo", "action_up");} return false;}});
Operation Result:

Continue at night












Android analysis view event distribution mechanism 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.