Android event distribution mechanism detailed _android

Source: Internet
Author: User
Tags gety static class

Before analyzing the Android event distribution mechanism, identify the two major types of Android's underlying control: view and ViewGroup. View is the normal control, there is no child layout, such as button, TextView. ViewGroup inherits from view, which means that you can have child controls, such as LinearLayout, ListView. Today we'll take a look at the event distribution mechanism for the view.
First look at the code, very simple, only a button, respectively, to it registered onclick and Ontouch click events.

Btn.setonclicklistener (New View.onclicklistener () {
      @Override public
      void OnClick (View v) {
        log.i ("Tag") "This is button OnClick event");
      }
    )
    ; Btn.setontouchlistener (New View.ontouchlistener () {
      @Override public
      boolean Ontouch (View V, motionevent Event) {
        log.i ("Tag", "This is button Ontouch action" + event.getaction ());
        return false;
      }
    });

Run the project and the results are as follows:
i/tag:this is button Ontouch Action0
I/tag:this is button Ontouch Action2
I/tag:this is button Ontouch Action2
I/tag:this is button Ontouch Action1
I/tag:this is button OnClick event
As you can see, Ontouch is performed before the onclick, so the order of events is first Ontouch, and then the onclick. Specifically why this, the following will be explained through the source code. At this point, we may have noticed that the Ontouch method has a return value, and here is the return false, and we change it to true again, and the result is as follows:
i/tag:this is button Ontouch Action0
I/tag:this is button Ontouch Action2
I/tag:this is button Ontouch Action2
I/tag:this is button Ontouch Action2
I/tag:this is button Ontouch Action1

Compared two times results, we found that the OnClick method is no longer implemented, why so, I will pass the source code to everyone step-by-step to clarify this idea.
When you look at the source, you first need to know that all view type control event portals are dispatchtouchevent (), so we'll go directly to the Dispatchtouchevent () method inside the view class.

public boolean dispatchtouchevent (Motionevent event) {//If the event should is handled by accessibility focus
    . if (Event.istargetaccessibilityfocus ()) {//We don ' t have focus or no virtual descendant has it, does not handle the
      Event.
      if (!isaccessibilityfocusedvieworhost ()) {return false;
      //We have focus and got the event, then with normal event dispatch.
    Event.settargetaccessibilityfocus (FALSE);
    Boolean result = false;
    if (minputeventconsistencyverifier!= null) {minputeventconsistencyverifier.ontouchevent (event, 0);
    Final int actionmasked = event.getactionmasked ();
    if (actionmasked = = Motionevent.action_down) {//Defensive cleanup for new gesture stopnestedscroll (); } if (Onfiltertoucheventforsecurity (event)) {//noinspection simplifiableifstatement listenerinfo li = mLi
      Stenerinfo; if (Li!= null && li.montouchlistener!= null &&  (Mviewflags & enabled_mask) = = ENABLED && Li.mOnTouchListener.onTouch (This, event)} {result
      = true;
      } if (!result && ontouchevent (event) {result = true; } if (!result && minputeventconsistencyverifier!= null) {Minputeventconsistencyverifier.onunhand
    Ledevent (event, 0);
    }//Clean up after nested scrolls if it is the end of a gesture;
    Also cancel it if we tried an action_down but we didn ' t want the rest/of the gesture.
        if (actionmasked = = Motionevent.action_up | |
        actionmasked = = Motionevent.action_cancel | | (actionmasked = = Motionevent.action_down &&!result))
    {Stopnestedscroll ();
  return result;

 }

From the 25th line of source code, you can see that the Montouchlistener.ontouch () method is first executed if Li!= null && li.montouchlistener!= null&& ( Mviewflags & enabled_mask) = = enabled&& Li.mOnTouchListener.onTouch (this, event) is true, result assignment is true, Otherwise, the Ontouchevent (event) method is executed.

From above you can see that there are four conditions to meet,
1, Listenerinfo Li, it is a static class in view, which defines the monitor of the view's events, and so on, so there are events involving view, Listenerinfo will be instantiated, so Li is not null
2, Montouchilistener is in the Setontouchlistener method to assign value, as long as the touch event is registered, Montouchilistener must not be null
3, (Mviewflags & enabled_mask) = = ENABLED, is to determine whether the currently clicked control is Enable, button defaults to enable, this condition is also constant to true,
4, the focus is, Li.mOnTouchListener.onTouch (this, event) is back to control the Ontouch method, when this condition is true, result=true, Ontouchevent (event) will not be executed. If Ontouch returns False, the Ontouchevent (event) method is executed again.
We then go into the Ontouchevent method to view the source code.

public boolean ontouchevent (Motionevent event) {final float x = Event.getx ();
    Final float y = event.gety ();
    Final int viewflags = mviewflags;
    Final int action = Event.getaction (); if ((ViewFlags & enabled_mask) = = DISABLED) {if (action = = motionevent.action_up && (mprivateflags ;
      pflag_pressed)!= 0) {setpressed (false);
      }//A disabled view is clickable still consumes the touch/events, it just doesn ' t respond to them. Return ((ViewFlags & clickable) = = Clickable | | (ViewFlags & long_clickable) = = long_clickable) | |
    (ViewFlags & context_clickable) = = context_clickable);
      } if (mtouchdelegate!= null) {if (Mtouchdelegate.ontouchevent (event)) {return true;
        } if ((ViewFlags & clickable) = = Clickable | |
        (ViewFlags & long_clickable) = = long_clickable) | | (ViewFlags & context_clickable) = = context_clickable){switch (action) {case MotionEvent.ACTION_UP:boolean prepressed = (Mprivateflags & PFLAG_PR
          epressed)!= 0;  if ((Mprivateflags & pflag_pressed)!= 0 | | prepressed) {//Take focus if we don ' t have it already and we
            should in//touch mode.
            Boolean focustaken = false; if (isfocusable () && isfocusableintouchmode () &&!isfocused ()) {Focustaken = Requestfocus ()
            ; } if (prepressed) {//The button is being released before we actually//showed I T as pressed.  Make it show the pressed//state now (before scheduling the click) to ensure//the user sees
              It.
            Setpressed (True, x, y); } if (!mhasperformedlongpress &&!mignorenextupevent) {//This is a tap, so remove the
            Longpress check Removelongpresscallback ();  Only perform take click Actions if we were to pressed state if (!focustaken) {/U Se a Runnable and post this rather than calling//PerformClick directly.
                This lets is the 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 Unset
            Pressedstate (); } if (prepressed) {postdelayed (munsetpressedstate, viewconfiguration.getpress
            Edstateduration ()); else if (!post (munsetpressedstate)) {//If the post failed, unpress right now munsetpressed
            State.run (); } removetapcallback();
          } mignorenextupevent = false;
        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 to//a short period in case this is a SC
          Roll.
            if (isinscrollingcontainer) {mprivateflags |= pflag_prepressed;
            if (Mpendingcheckfortap = = null) {Mpendingcheckfortap = new Checkfortap ();
            } mpendingcheckfortap.x = Event.getx ();
            MPENDINGCHECKFORTAP.Y = Event.gety ();
          Postdelayed (Mpendingcheckfortap, Viewconfiguration.gettaptimeout ()); else {//not inside a scrolling container, so show the FeedbAck right away setpressed (true, x, y);
          Checkforlongclick (0);
        } break;
          Case MotionEvent.ACTION_CANCEL:setPressed (FALSE);
          Removetapcallback ();
          Removelongpresscallback ();
          Mincontextbuttonpress = false;
          Mhasperformedlongpress = false;
          Mignorenextupevent = false;
        Break
          Case MotionEvent.ACTION_MOVE:drawableHotspotChanged (x, y); Be lenient about moving outside of buttons if (!pointinview (x, Y, Mtouchslop)) {//Outside Butto
            n Removetapcallback (); if ((Mprivateflags & pflag_pressed)!= 0) {//Remove any future long Press/tap checks REM
              Ovelongpresscallback ();
            Setpressed (FALSE);
      }} break;
    return true;
  return false;

 }

From the 21 lines of the source code we can see that the control can be clicked into the switch judgment, when we trigger the finger to leave the actual, it will go into the motionevent.action_up case. We then look down, in the 50 line of the source code, called to the Mperformclick () method, we continue to enter the source of this method to see.

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;
  }

Now we can see that the OnClick method is invoked as long as listenerinfo and monclicklistener are not NULL, and that the listenerinfo is not NULL as long as there is a listener event. Where is the band Monclicklistener assigned? We will continue to look at its source code.

public void Setonclicklistener (@Nullable onclicklistener l) {
    if (!isclickable ()) {
      setclickable (true);
    }
    getlistenerinfo (). Monclicklistener = l;
  }

It's clear to see that when we call the Setonclicklistener method to register a click event with the button, the Monclicklistener is assigned a value. The order of the entire distribution event is Ontouch ()-->ontouchevent (event)-->performclick ()-->onclick ().
Now we can solve the problem before.
1, Ontouch method is preferred to the onclick, so is the implementation of the Ontouch, and then the execution of the onclick.
2, whether it is dispatchtouchevent or ontouchevent, if the return of true means that this event has been consumed, processed, no longer down the pass. As you can see in Dispathtouchevent's source code, if Ontouchevent returns True, it also returns true. If Dispatchtouchevent returns True when Ontouch listens, Ontouch returns True, and the event is consumed in advance by Ontouch. No longer execute the ontouchevent, let alone the onclick monitor.

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

Related Article

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.