Detailed analysis of Ontouch event transfer mechanism in Android _android

Source: Internet
Author: User
Tags event listener gety

Ontach Introduction

Ontach is the foundation of the entire event mechanism in the Android system. Other events in Android, such as OnClick and Onlongclick, are based on Ontach.

The Ontach includes the entire process of pressing from the fingers to the screen of the cell phone, in microscopic form, as Action_down, Action_move and action_up.

The two main definitions of Ontach are as follows:

1. In custom controls, there are common overriding onTouchEvent(MotionEvent ev) methods. As you can often see in development, the Ontouchevent method of rewriting

And there are corresponding judgments for different microscopic manifestations (Action_down, action_move, ACTION_UP, etc.), which perform logic and may return different Boolean values.

2. In code, set the Setontouchlistener listener directly on the existing control. and rewrite the listener's Ontouch method. There are view and motionevent in the Ontouch callback function

Ontouch Event Delivery mechanism

As we all know, the UI controls we use are inherited from the common parent class--view. So view this class should be in charge of the related processing of the Ontouch event. So let's take a look: Find the touch-related methods in the view, one of which is easy to draw our attention to: dispatchTouchEvent(MotionEvent event) .

According to the means of the method name should be responsible for distributing touch events, the following is given the source code:

/** * Pass the touch screens motion event down 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 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 = mlistenerinfo;  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.onunhandledevent (E
 vent, 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; }

The source is a bit long, but we don't have to look at every line. First, notice that the return value of the Dispatchtouchevent is a Boolean, and the explanation on the annotation :@return True if the event was handled by the view, false otherwise. means that if the touch event is consumed by this view, it returns TRUE, otherwise it returns false. The method first determines whether the event has the focus, and returns False if the focus is not received directly. Then let's turn our eyes to if (li != null && li.mOnTouchListener != null&& (mViewFlags & ENABLED_MASK) == ENABLED&& li.mOnTouchListener.onTouch(this, event)) this fragment and see that there is a local variable called Li, belonging to the Listenerinfo class, which is worth mlistenerinfo. Listenerinfo is just a wrapper class that encapsulates a large number of listeners.

To find Mlistenerinfo in the View class, you can see the following code:

Listenerinfo Getlistenerinfo () {
 if (mlistenerinfo!= null) {return
 mlistenerinfo;
 }
 Mlistenerinfo = new Listenerinfo ();
 return mlistenerinfo;
}

So we can know that Mlistenerinfo is not empty, so Li is not empty, the first judgment is true, And then see Li.montouchlistener, said earlier Listenerinfo is a listener's encapsulation class, so we also go to track Montouchlistener:

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

It is through the above methods to set the Montouchlistener, I think the above methods are certainly very familiar with it, it is our usual use of xxx.setontouchlistener, All right, we know it. If Ontouchlistener is set, the second is true, and the third is true if the view is enable and the default is enable. There is one last: li.mOnTouchListener.onTouch(this, event) obviously the method that recalls the listener in the second judgment onTouch() , and if the onTouch() method returns True, all four of the above judgements are true, the dispatchTouchEvent() method returns True, and if (!result && onTouchEvent(event)) the judgment is not executed And in this judgment we see a familiar method: onTouchEvent() . So if you want to perform a ontouchevent, you must have at least one false in the four judgments above.

Let's assume that we onTouch() are returning false in the method so that we can execute the ontouchevent smoothly, then look at the ontouchevent source code:

/** * Implement this method to handle the screen motion events. * <p> * If This was used to detect click Actions, it's recommended that * the actions are performed by imple Menting and calling * {@link #performClick ()}. This would ensure consistent system behavior, * including: * <ul> * <li>obeying Click Sound Preferences * & Lt;li>dispatching Onclicklistener calls * <li>handling {@link Accessibilitynodeinfo#action_click ACTION_
 CLICK} when * accessibility features are enabled * </ul> * * @param event The motion event.
 * @return True If the event was handled, false otherwise.
 * * 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 & PFL
 ag_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 Pre
  Pressed = (Mprivateflags & pflag_prepressed)!= 0; if ((Mprivateflags & pflag_pressed)!= 0 | | prepressed) {//Take focus if we don ' t have it already and we should I
   N//Touch mode.
   Boolean focustaken = false;
   if (isfocusable () && isfocusableintouchmode () &&!isfocused ()) {Focustaken = Requestfocus (); } 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.
   Setpressed (True, x, y);
   } if (!mhasperformedlongpress &&!mignorenextupevent) {//This are a tap, so remove the Longpress check

   Removelongpresscallback (); Only perform take click Actions if we were to pressed state if (!focustaken) {//Use a Runnable and post th is 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 unsetpressedstate ();
   } if (prepressed) {postdelayed (munsetpressedstate, Viewconfiguration.getpressedstateduration ()); else if (!post (munsetpressedstate)) {//If The post failed, unpress right now Munsetpressedstate.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 scroll.
   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; CaseMotionEvent.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 button removetapcal
   Lback (); if ((Mprivateflags & pflag_pressed)!= 0) {//Remove any future long Press/tap checks Removelongpresscallback ()

   ;
   Setpressed (FALSE);
 }} break;
 return true;
return false; }

The source code is longer than the dispatchtouchevent, but we are also looking at the focus:
if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE)
see this sentence will probably know the main is to determine whether the view is clickable, if you can click then execute, or return directly false. You can see if the switch is used to determine which kind of touch event is in the IF, but it returns true at the end.

One more thing to note: The method is executed in action_up performClick() :

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

Can see above li.mOnClickListener.onClick(this); , yes, we seem to have a new discovery. Based on the above experience, this code will go back to our set up Click event Listener. Which is what we usually use.xxx.setOnClickListener(listener);

/**
 * Register A callback to be invoked as this view is clicked. If This view isn't
 * clickable, it becomes clickable.
 *
 * @param l The callback that'll run
 *
 @see #setClickable (Boolean)/
 public
void Setonclicklis Tener (@Nullable onclicklistener l) {
 if (!isclickable ()) {
 setclickable (true);
 }
 Getlistenerinfo (). Monclicklistener = l;
}

We can see that the above method setting is exactly the Mlistenerinfo click Listener, verifying the above conjecture. Here Ontouch the transmission mechanism of the event has been basically completed, and it is a conclusion.

OK, so we can solve the problem of the beginning, by the way let's make a summary: in Dispatchtouchevent, if the Ontouchlistener is set and the view is enable, Then the first to be executed is the Ontouchlistener onTouch(View v, MotionEvent event) . If Ontouch returns True, the Dispatchtouchevent no longer executes and returns TRUE, otherwise the ontouchevent is executed, and if the view is clickable in Ontouchevent, it returns TRUE or false. In Ontouchevent, if the view is clickable and the current touch event is action_up, the performClick() onclick method of the callback Onclicklistener is executed.

Here is a sketch of my drawing:

It is also noteworthy that if the current event is Action_down, the view will receive the next ACTION_MOVE,ACTION_UP event only if the Dispatchtouchevent returns True. This means that only events are consumed to receive the next event.

Summarize

The above is about Android Ontouch event delivery mechanism of detailed analysis, I hope that the Android developers of the study or work can have some help, if you have questions you can message exchange.

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.