Android event-Passing mechanism _android

Source: Internet
Author: User

Experimental environment

OS X 10.9
Eclipse (ADT)
Android Source version: API level (Android 4.4)

Android Event composition

In Android, events include Dots, long press, drag, slide, etc., click and double-click, and also include a single point of operation and multiple-fingered operation. All of this constitutes an event response in Android. In general, all events are based on the following three sections:

Press (Action_down)
Move (Action_move)
Lift Up (ACTION_UP)

All action events must first be performed by pressing the action (Actiondown), after which all operations are based on a press operation, and when the press operation completes, the next step may be a move (actionmove) and then lift (ACTION_UP), Or you can lift it directly after the operation is done without moving. This series of actions can be controlled in Android.

We know that all of the event operations happen on the touchscreen, and the on-screen interaction with us is a variety of view components (view), in which all views are inherited from view and the view is laid out through various layout components (ViewGroup). ViewGroup also inherits from view. All UI controls, such as button, TextView, are inherited from view, and all layout controls such as Relativelayout, container controls, such as ListView, inherit from ViewGroup. So, the main thing about our event operations is between view and ViewGroup, so what are the main ways to respond to these events in view and ViewGroup? Remember the following 3 methods, which we can see by looking at the source code of view and ViewGroup:

View.java

public boolean dispatchtouchevent (Motionevent event)

Viewgroup.java

public boolean dispatchtouchevent (Motionevent event) public
Boolean ontouchevent (Motionevent event) 
public Boolean onintercepttouchevent (Motionevent event)

There are dispatchtouchevent and Ontouchevent methods in both view and ViewGroup, but in ViewGroup there is a onintercepttouchevent method, so what are these methods? Don't worry, let's take a look at their return value first. The return values of these methods are all Boolean, why is the Boolean, look at the title of this article, "Event delivery", the process of passing is one after another, that to a certain point will continue to pass down after it? Did you find that the word "whether" is determined by Boolean as the return value. Yes, all of these methods return True or FALSE. In Android, all events are consumed from the start through to the completion of events, and the return value of these methods determines whether an event continues to be transmitted, intercepted, or consumed.

The next step is the parameters of these methods, which accept a motionevent type of argument, Motionevent inherited from InputEvent, to mark various action events. The previously mentioned Actiondown, Actionmove, and action_up are constants defined in Motinevent. We judge which type of event is received by motionevent the type of event passed in. Up to now, the return values and parameters of these three methods you should all understand, and then explain how each of these three methods handles the event.

The Dispatchtouchevent method is used for the distribution of events, all events in Android must be distributed by this method, and then decide whether to consume the current event itself or continue to distribute it to the child control process. Returns true to indicate that no distribution has been continued and that the event has not been consumed. return false to continue distributing, and if it is viewgroup, distribute to onintercepttouchevent to determine whether to intercept the event.

The Ontouchevent method is used for handling the event, returning true to indicate that the consumption is handling the current event, returning false to not processing, and giving the child control a continuation distribution.
Onintercepttouchevent is a ViewGroup method, the view does not, its role is responsible for the interception of events, return True when the interception of the current event, do not continue to distribute, to their own ontouchevent for processing. Returns false without intercepting, and continues to pass down. This is a viewgroup-specific approach because there may be a child view in the ViewGroup, and the view in Android can no longer contain child view (iOS).
So far, the composition of Android events and the role of event handling methods you should be more clear, and then we will use a demo to actually experience the experiment.

Android Event handling

First create a new project in Eclipse and create a new class Rtbutton inheritance button to implement our tracking of button events.

Rtbutton.java

public class Rtbutton extends Button {public Rtbutton (context, AttributeSet attrs) {Super (context, attrs);} @O Verride public boolean dispatchtouchevent (Motionevent event) {switch (event.getaction ()) {case Motionevent.action_down
: System.out.println ("Rtbutton---dispatchtouchevent---down");
Break
Case MotionEvent.ACTION_MOVE:System.out.println ("Rtbutton---dispatchtouchevent---move");
Break
Case MotionEvent.ACTION_UP:System.out.println ("Rtbutton---dispatchtouchevent---up");
Break
Default:break;
Return Super.dispatchtouchevent (event); @Override public boolean ontouchevent (Motionevent event) {switch (event.getaction ()) {case MotionEvent.ACTION_DOWN:Sy
Stem.out.println ("Rtbutton---ontouchevent---down");
Break
Case MotionEvent.ACTION_MOVE:System.out.println ("Rtbutton---ontouchevent---move");
Break
Case MotionEvent.ACTION_UP:System.out.println ("Rtbutton---ontouchevent---up");
Break
Default:break;
Return Super.ontouchevent (event); }
}

In Rtbutton I rewrote the dispatchtouchevent and Ontouchevent methods, and got motionevent each event state, printing and outputting information in each state. Then put the custom button Rtbutton in the Activity_main.xml directly under the root layout.

Activity_main.xml

<linearlayout xmlns:android= "http://schemas.android.com/apk/res/android"
xmlns:tools= "http:// Schemas.android.com/tools "
android:id=" @+id/mylayout "
android:layout_width=" Match_parent "
android: layout_height= "Match_parent" >
<com.ryantang.eventdispatchdemo.rtbutton 
android:id= "@+id/btn"
android:layout_width= "match_parent"
android:layout_height= "wrap_content"
android:text= "button"/ >
</LinearLayout>

The next step is to set up Ontouch and onclick listeners in the activity to track the process of event passing, and there is also a dispatchtouchevent method and a Ontouchevent method in the Rtbutton. We also rewrite them and output print information.

Mainactivity.java

public class Mainactivity extends activity {private Rtbutton button; @Override protected void onCreate (Bundle savedinsta Ncestate) {super.oncreate (savedinstancestate); Setcontentview (r.layout.activity_main); button = (RTButton)
This.findviewbyid (R.ID.BTN); Button.setontouchlistener (New Ontouchlistener () {@Override public boolean ontouch (View V, motionevent event) {switch (EV Ent.getaction ()) {case MotionEvent.ACTION_DOWN:System.out.println ("Rtbutton---ontouch---down");
MotionEvent.ACTION_MOVE:System.out.println ("Rtbutton---ontouch---move");
Break
Case MotionEvent.ACTION_UP:System.out.println ("Rtbutton---ontouch---up");
Break
Default:break;
return false;
}
}); Button.setonclicklistener (New Onclicklistener () {@Override public void OnClick (View v) {System.out.println ("Rtbutton
Clicked! ");} @Override public boolean dispatchtouchevent (Motionevent event) {switch (event.getaction ()) {case Motionevent.action_ DOWN:SYSTEM.OUT.PRINTLN ("Activity---DispatchtouchevENT---down ");
Break
Case MotionEvent.ACTION_MOVE:System.out.println ("Activity---dispatchtouchevent---move");
Break
Case MotionEvent.ACTION_UP:System.out.println ("Activity---dispatchtouchevent---up");
Break
Default:break;
Return Super.dispatchtouchevent (event); @Override public boolean ontouchevent (Motionevent event) {switch (event.getaction ()) {case MotionEvent.ACTION_DOWN:Sy
STEM.OUT.PRINTLN ("Activity---ontouchevent---down");
Break
Case MotionEvent.ACTION_MOVE:System.out.println ("Activity---ontouchevent---move");
Break
Case MotionEvent.ACTION_UP:System.out.println ("Activity---ontouchevent---up");
Break
Default:break;
Return Super.ontouchevent (event); }
}

The Code section is complete, and then the project is run and the button is clicked to view the log output, and we can see the following results:

As you can see through the log output, you first perform the activity's Dispatchtouchevent method for event distribution, In line 55th of the Mainactivity.java code, the return value of the Dispatchtouchevent method is Super.dispatchtouchevent (event), so the parent class method is invoked. We enter the Activity.java of the source code to see the specific implementation.

Activity.java

/**
* Called to process with screen events. You can override this to
* intercept all touch screens events before they are dispatched to the
* window. Be sure to call this implementation for touch screen events
* should is handled normally.
* 
@param ev the touch screen event.
* 
* @return Boolean return True if this event is consumed.
*/Public
Boolean dispatchtouchevent (motionevent ev) {
if (ev.getaction () = = Motionevent.action_down) {
onuserinteraction ();
}
if (GetWindow (). superdispatchtouchevent (EV)) {return
true;
}
return ontouchevent (EV);
}

As you can see from the source, the Dispatchtouchevent method only deals with the Actiondown event, as mentioned earlier, all events are based on the start, so Android believes that when Actiondown events are not executed, the following events are meaningless , so here we first judge the Action_down event. If the event is set up, the Onuserinteraction method is invoked, which can be overridden in the activity and invoked before the event is distributed. The return value of the method is void, does not affect the event-passing result, and then determines the execution result of the GetWindow (). superdispatchtouchevent (EV) to see its source code:

Activity.java

/**
* Used by custom windows, such as Dialog, to pass the touch screen event
* Further down the view hierarchy. Application developers should
* not need to implement or call this.
*
*
/Public Abstract Boolean superdispatchtouchevent (Motionevent event);

Through the source annotation we can learn that this is an abstract method for customizing Windows, such as customizing dialog passing touch events, and mentioning that the developer does not need to implement or invoke the method, the system will complete, If we set the return value of the Dispatchtouchevent method to true in mainactivity, the result here is true, so that the execution ontouchevent (EV) is not returned, and if False is returned here, Then it will eventually return to the execution Ontouchevent method, so that the next thing to be called is the Ontouchevent method. Don't worry, the log output information can be seen, action_down events from the activity was distributed to the Rtbutton, followed by the implementation of the Ontouch and Ontouchevent methods, why first to execute the Ontouch method? We go to the Rtbutton in the dispatchtouchevent to see how the source code in view is handled.

View.java

/** * Pass the touch screen motion event down to the target view, or this * view if it I
s 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 (minputeventconsistencyverifier!= null) {Minputeventconsis
Tencyverifier.ontouchevent (event, 0); } if (Onfiltertoucheventforsecurity (event)) {//noinspection simplifiableifstatement listenerinfo li = mListenerInfo; if (Li!= null && li.montouchlistener!= null && (Mviewflags & enabled_mask) = = ENABLED && Li.mon
Touchlistener.ontouch (this, event)) {return true;} if (Ontouchevent (event)) {return true;}} if (minputeventconsistencyverifier!= null) {minputeventconsistencyverifier.onunhandledevent (event, 0);} return False
; }

Select the key code for analysis, you can see the code line 16th, there are several conditions, the method returns True when several conditions are met, When the condition Li.montouchlistener is not empty, by looking in the source code, it is found that Montouchlistener is set in the following methods.

View.java

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

This method is already familiar with the Ontouchlistener we set for Rtbutton in Mainactivity.java (Mviewflags & enabled_mask) = = Enable determines whether the current view is enabled and by default is enabled. Then there is the Li.mOnTouchListener.onTouch (this, event) condition, where the Ontouch method is called, The invocation of this method is the listener callback that we set for Rtbutton in Mainactivity.java, and if the method returns true, the entire condition is satisfied and dispatchtouchevent returns True, indicating that the event does not continue to distribute downward because it has been ontouch eliminated Fee.

If Ontouch returns false, the judgment condition is not established, and then the Ontouchevent (event) method is used to determine if the method returns True, indicating that the event was Ontouchevent handled. The entire dispatchtouchevent returns TRUE. Here, we can answer the previous question "Why do the Ontouch method first". So far, the Actiondown events have been distributed from activity to Rtbutton, then processed by Ontouch and ontouchevent, and eventually The Actiondown incident was handed over to Rtbutton ontouchevent for processing.

Actionup event occurs when our hands (the genymotion that I use here then do with the mouse, with the hands that may perform some actionmove operations) are raised from the screen. From the previous output of the log confidence can be seen, the Actionup event also from the activity started to Rtbutton for distribution and processing, and finally, because we registered the OnClick event, when Ontouchevent executed, the OnClick event was invoked, So where is the onclick called? Continue to search the source code of View.java. Because ontouchevent in the View.java in the source is longer, here is not posted, interested can go to study for themselves, through the source read, we in the Actionup processing branch can see a PerformClick () method, From the source of this method you can see what has been done.

View.java

/**
* Call this view ' s Onclicklistener, if it is defined. Performs all normal
* actions associated with clicking:reporting accessibility event, playing
* a sound, etc.
   
    *
* @return True There was a assigned onclicklistener this was called, false
* Otherwise is returned.
* * Public
Boolean PerformClick () {
sendaccessibilityevent (accessibilityevent.type_view_clicked);
Listenerinfo li = mlistenerinfo;
if (Li!= null && li.monclicklistener!= null) {
playsoundeffect (soundeffectconstants.click);
Li.mOnClickListener.onClick (this);
return true;
}
return false;
}
   

In the IF branch you can see the execution of Li.mOnClickListener.onClick (this), which executes the OnClick method we implemented for Rtbutton, so so far, we can answer the previous one. Where was the onclick called? "The problem was that the onclick was executed in the ontouchevent, and that the onclick was to be executed after Ontouch."

In this case, the click of the button to pass the event is over, we spy on the implementation details of the source code, if we modify the various event control method return value what happens, with this problem, into the next section of the discussion.

Android Event interception

From the previous analysis, we learned what types of events exist in Android, how events are delivered, and what to do with the source. We can see that in Android, events are passed hierarchically, and an event pass corresponds to a complete hierarchical relationship, such as the Actiondown event that is parsed in the previous section from activity to Rtbutton,actionup events. Combined with the source analysis of the various event processing methods, you can clearly see the process of handling events.

As mentioned before, the return value of all event-handling methods is Boolean, and now we're going to modify the return value, starting with the activity, and, based on the previous log output, the first thing to do is the Dispatchtouchevent method Now modify the previous return value Super.dispatchtouchevent (event) to true, and then recompile the run and click the button to see the following log output.

As you can see, the event execution to the Dispatchtouchevent method has not been further distributed, which also validates the previous claim that, when returning true, it is no longer possible to continue distributing, from the dispatchtouchevent source of the previously analyzed activity , the Ontouchevent method is not executed when True is returned.

Next, restore the above modifications, let the events continue to distribute in the activity, and then distribute to Rtbutton, modify the return value of the Rtbutton Dispatchtouchevent method to True, recompile the run, and view the output log results.

As you can see from the results, events are not being distributed further down the Dispatchtouchevent method of Rtbutton. The above modifications are then restored and the Rtbutton Ontouchevent method return value is modified to true to consume the event, based on the previous analysis, the OnClick method is invoked in the Ontouchevent method, When the event is consumed, the OnClick method will not be invoked, and the compilation runs, resulting in the following log output.

As with the analysis results, the OnClick method was not executed because the event was consumed in the Rtbutton ontouchevent method. The following figure is the flowchart for the entire event pass.

So far, the event interception mechanism in Android has been analyzed. But here we only discuss the single layout structure of the single control situation, if it is nested layout, then what is the situation? Next, we will explore and analyze the Android event-passing mechanism in the context of nested layouts.

Android Nested Layout event delivery

First, a new class rtlayout inherits from LinearLayout, also overrides the Dispatchtouchevent and Ontouchevent methods, and, in addition, overrides the Onintercepttouchevent method, which is described at the beginning of the article , this method only exists in the ViewGroup and its subclasses, and is to control the need to intercept events. Don't confuse this with dispatchtouchevent, which controls the distribution of events, and the latter is executed first.

So, is the event passed to the view first, or is it passed to the ViewGroup first? We can draw a conclusion from the following analysis. First, we need to make some changes to the engineering code.

Rtlayout.java

public class Rtlayout extends LinearLayout {public rtlayout (context, AttributeSet attrs) {Super (context, attrs)
; @Override public boolean dispatchtouchevent (Motionevent event) {switch (event.getaction ()) {case Motionevent.action_d
OWN:System.out.println ("Rtlayout---dispatchtouchevent---down");
Break
Case MotionEvent.ACTION_MOVE:System.out.println ("Rtlayout---dispatchtouchevent---move");
Break
Case MotionEvent.ACTION_UP:System.out.println ("Rtlayout---dispatchtouchevent---up");
Break
Default:break;
Return Super.dispatchtouchevent (event); @Override public boolean onintercepttouchevent (Motionevent event) {switch (event.getaction ()) {case Motionevent.actio
N_DOWN:System.out.println ("Rtlayout---onintercepttouchevent---down");
Break
Case MotionEvent.ACTION_MOVE:System.out.println ("Rtlayout---onintercepttouchevent---move");
Break
Case MotionEvent.ACTION_UP:System.out.println ("Rtlayout---onintercepttouchevent---up");
Break
Default:break; Return Super.onintercePttouchevent (event); @Override public boolean ontouchevent (Motionevent event) {switch (event.getaction ()) {case Motionevent.action_down:s
Ystem.out.println ("Rtlayout---ontouchevent---down");
Break
Case MotionEvent.ACTION_MOVE:System.out.println ("Rtlayout---ontouchevent---move");
Break
Case MotionEvent.ACTION_UP:System.out.println ("Rtlayout---ontouchevent---up");
Break
Default:break;
Return Super.ontouchevent (event); }
}

Also, add a parent layout to Rtbutton in the layout file, indicating the custom rtlayout, and the modified layout file as follows.

Activity_main.xml

<linearlayout xmlns:android= "http://schemas.android.com/apk/res/android"
xmlns:tools= "http:// Schemas.android.com/tools "
android:layout_width=" match_parent "
android:layout_height=" Match_parent " >
<com.ryantang.eventdispatchdemo.rtlayout
android:id= "@+id/mylayout"
android:layout_width= " Match_parent "
android:layout_height=" match_parent ">
<com.ryantang.eventdispatchdemo.rtbutton
android:id= "@+id/btn"
android:layout_width= "match_parent"
android:layout_height= "Wrap_content"
android:text= "button"/>
</com.ryantang.eventdispatchdemo.RTLayout>
</linearlayout >

Finally, we set the Ontouch and onclick events for rtlayout in the activity and add the following code to the mainactivity.

Mainactivity.java

Rtlayout.setontouchlistener (New Ontouchlistener () {
@Override public
boolean Ontouch (View V, motionevent Event) {
switch (event.getaction ()) {case
Motionevent.action_down:
System.out.println (" Rtlayout---ontouch---down ");
break;
Case Motionevent.action_move:
System.out.println ("Rtlayout---ontouch---move");
break;
Case MOTIONEVENT.ACTION_UP:
System.out.println ("Rtlayout---ontouch---up");
break;
Default: Break
;
}
return false;
}
});
Rtlayout.setonclicklistener (New Onclicklistener () {
@Override public
void OnClick (View v) {
System.out.println ("Rtlayout clicked!");
}
);

After the code has been modified, compile and run the project, again, click on the button to view the log output as follows:

From the log output we can see that after nesting the rtlayout, the sequence of events passed into Activity->rtlayout->rtbutton, which answers the previous question, In Android, event passing is passed from ViewGroup to view, not in turn.

From the output of the third row can be seen, the implementation of the Rtlayout Onintercepttouchevent method, the role of the method is to determine whether to intercept the event, we go to the ViewGroup source code to see the implementation of the method.

Viewgroup.java

public boolean onintercepttouchevent (Motionevent ev) {return
false;
}

The implementation of this method is simple and returns only one false. So where is this method called, through the log output analysis can be seen in the Rtlayout dispatchtouchevent execution, then we go into the dispatchtouchevent source code inside to see. Because the source is relatively long, I will intercept the key parts of it for explanation.

Viewgroup.java

Check for interception.
Final Boolean intercepted;
if (actionmasked = = Motionevent.action_down
| | | mfirsttouchtarget!= NULL) {
final Boolean disallowintercept = (MG Roupflags & Flag_disallow_intercept)!= 0;
if (!disallowintercept) {
intercepted = onintercepttouchevent (EV);
Ev.setaction (action);  Restore action in case it is changed
} else {
intercepted = false;
}
} else {
//There are no Touch the targets and this action are not a initial down
//So the view group continues to intercept touches.
intercepted = true;
}

From this part of the code you can see that the return value is assigned to intercepted after the Onintercepttouchevent call, which controls whether the event is to be distributed to its child controls, so it acts as a blocking function. If Onintercepttouchevent returns false, it is not intercepted, and if true, the current event is blocked. We will now modify the return value of the method in Rtlayout to true and recompile the run, then click the button to see the output as shown below.

Can see, we clearly clicked the button, but the output results show Rtlayout Click event was executed, and then through the output analysis, compared to the last output, found that this time the output is completely without rtbutton information, yes, Since the Onintercepttouchevent method returns True, the event is intercepted here, so he will not continue to distribute it to Rtbutton, instead handing it over to his own ontouchevent method for granted, The last thing to do is the Rtlayout click event.

Summarize

The above we analyze the Android event delivery mechanism, and explore the process of event transmission in combination with the system source code. Through the single layout and nested layout of the event delivery and processing are analyzed, summarized as follows:

In Android, event delivery is passed from top to bottom, and event handling begins with activity to ViewGroup to view.
The event-passing methods include Dispatchtouchevent, Ontouchevent, Onintercepttouchevent, where the first two are both view and ViewGroup, and the last one is the only ViewGroup method. These three methods are responsible for event distribution, event handling, event interception, respectively.
The Ontouch event is to be executed before the OnClick event, Ontouch in the event distribution method Dispatchtouchevent, and the onclick is invoked in the event-handling method Ontouchevent. Ontouchevent the call to the Dispatchtouchevent method.

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.