Understanding the Android event distribution mechanism

Source: Internet
Author: User
Tags ming

Recall, what are the most common things that we are exposed to in Android development? Obviously, in addition to activity, there are various kinds of controls (that is, view).
At the same time, the cause of the birth of an app is to complete various interactions with the user according to different needs. The so-called interaction, the essence is the friendly response to the user's various operational behavior.
So there are times when a control (View) appears on the screen, usually not just for the sake of the device, but also for responding to the user's actions.
In the most basic case: Now there is a button in one of the interfaces, and every time the user clicks the button, our program will respond.
So, if we restore the "click button" behavior, it can be seen as a matter of fact: the user's finger and the screen where the button is located in a certain kind of contact.
So simply put, we can make the user touch the screen every time, as a "touch event." And for each "touch event" response processing, it constitutes the so-called "interaction."
As a result, one of the things we want to figure out today in this article is the "Android event distribution mechanism." Then, we walk into it step-by-step.

Why do I need to distribute?

Before we start, let's consider a problem. That is why we find that this knowledge point is always described as "event distribution" rather than "event handling"? Think of the following:

Xiao Ming registered a company to start his own entrepreneurial journey. This day, a customer came to Xiao Ming's company brought the first single business. We can treat "this business" as a "touch event".
Xiao Ming le bad, hurriedly began to start this single business. In response, we can understand the handling of "touch events". Yes, so far we have not found anything related to "distribution".
In fact, it is not difficult to imagine that there is no "distribution" of related things, because now the company only xiaoming alone, in addition to their own treatment, he has no choice.
For the word "distribution" itself is based on a certain number. For example, Xiao Ming's company through the development to expand to 10 people's scale, divided the department. There's a new business coming up this day.
At this time, Xiaoming has a lot of options, he can choose to deal with this business, of course, you can also choose to distribute the business to the staff to deal with. This is what we call "distribution."

This case is the same for Android, and if we can guarantee that there will always be only one view on the current screen, there's nothing left to do with touch events.
But it is clear that there is usually no single "only one" in an interface, which involves a combination of non-quantitative View (viewgroup) . This time when "event" occurs, it is not so easy to deal with.
This is actually why, "the event distribution mechanism of Android" is a knowledge point that we must master from rookie to advanced.
But actually it doesn't matter, when we understand the "Xiao Ming entrepreneurship" This example, actually has mastered the basic principle of event distribution.

See how events are distributed?

We say that all interactions with the user are generated in the mobile screen, which is an interface. And the Android interface elements, nothing more than view and ViewGroup.
At the same time, another key point we focus on is the "touch event" that represents the action behavior, which corresponds to the English language as if it were "touchevent."
OK, in our present two eyes a blind situation. Try using "touchevent" as the keyword to study the research-related methods in the view and ViewGroup classes.

Finally, here are a few of the methods we need to understand, which are also the principle of the event distribution mechanism:

  • Dispatchtouchevent
  • Ontouchevent
  • Onintercepttouchevent (exists only in viewgroup)

OK, so far we don't quite understand the specific role of these methods. Just know that if you look at the names individually, they appear to represent a similar role for distribution, processing, and interception, respectively.

Where is the origin?

From now on, we are going to take a formal step-by-step study of the process of a touch event. Let's first look at a very basic but Representative layout:

<?xml version= "1.0" encoding= "Utf-8"?><linearlayout xmlns:android="Http://schemas.android.com/apk/res/android"  Android:tag="group_a"android:layout_width="Match_parent"android:layout_ Height="Match_parent"android:orientation="vertical">                    <linearlayoutandroid:tag= "group_b"android:layout_width="Match_ Parent "android:layout_height="match_parent "android:orientation=" Vertical " >                                        <buttonandroid:tag="View"android:layout_width="Wrap_ Content "android:layout_height=" wrap_content " />                                        </linearlayout></linearlayout>

But if so, we are still unable to study the distribution of its events, so we customize two classes to inherit the LinearLayout and the button class, respectively.
And the work we're going to do is simple, in the same way that we mentioned earlier about "event distribution," with a log print similar to the following:

LOG.D (Gettag (). toString (), "ontouchevent");

We then replace the LinearLayout and button in the layout file with our own defined classes. At this point, after we run the program, click on the button to get the following log:

Group_a:dispatchtouchevent
Group_a:onintercepttouchevent
Group_b:dispatchtouchevent
Group_b:onintercepttouchevent
View:dispatchtouchevent
View:ontouchevent

Can't eat a fat man, we are here to focus on only one point, that is: When we click on the button, the first trigger is "group_a" is the outermost layout of the Dispatchtouchevent method. This truth is not difficult to understand, just like "Xiao Ming Entrepreneurship", if a single business comes, nature should be first by the highest level of "Xiao Ming" know.

That is, when a "touch event" is generated, it is first routed to the topmost view. This may seem reasonable, but it is not difficult to think of the "top-level" words:
So, all of our view, our entire layout file, actually has a carrier, and that's its host activity. Because you must remember "Setcontenview (R.LAYOUT.XXX)".
So, let's imagine if the "touch event" was first transmitted to the activity? Open the source of activity we are pleasantly surprised to find: It also contains dispatchtouchevent and Ontouchevent methods. OK, what we're going to do, naturally, is to overwrite the two methods in our Activity class, plus log printing, and run the test again to get the following log:

Mainactivity:dispatchtouchevent
Group_a:dispatchtouchevent
Group_a:onintercepttouchevent
Group_b:dispatchtouchevent
Group_b:onintercepttouchevent
View:dispatchtouchevent
View:ontouchevent

Through the logs, it is easy to see that, as we speculate, when touch events are generated, it is really the first thing to pass to the activity.
At this time, the mention of "Xiao Ming" again. Yes, when there is a business coming, must first reach the "Company" level, and then the supreme director of "Xiao Ming."

Open the Activity class Dispatchtouchevent source code as follows:

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

The focus of our attention is on the following line of code. As a result, we find that when the activity receives a touch event, the event is distributed through the window to which it belongs.

if (getWindow().superDispatchTouchEvent(ev))

Window itself is an abstract class, and its superdispatchtouchevent is an abstract method. Its only implementation exists in the Phonewindow class.
And in Phonewindow, the realization of superdispatchtouchevent is this:

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

That is, the distribution of events is passed to Mdecor, the so-called "Decorview" in the Android View structure, and Decorview itself is framelayout.
So the nature of the distribution of events at this time is simple, and it returns to Framelayout, the ViewGroup event distribution.

p.s: Decorview involves the knowledge of the Android UI interface architecture. We can usually understand the simplest as a activiy is an interface.

But as we become more familiar with Android, we can easily guess, in fact, not just that. So we can simply understand:

  • The activity is attached to the Phonewindow; this one will wrap a decorview (translation is a decorative view), which is itself a framelayout.
    (So, we can actually understand that Decorview is really the top-most parent view in our interface)
  • At the same time, generally speaking, there will be two sub-view in Decorview, namely: Titleview and Contentview.
  • Among them, Titleview is simply the column we call Actionbar (titlebar). And Contentview we are familiar with: "Setcontenview (R.LAYOUT.XXX)"

Okay, so here we summarize our current harvest, which is simple:
When a "touch event" is generated, it is first passed to the current activity. The activity, through its owning window, finds the Decorview in which it begins to distribute the event progressively.

Continue delivery

Recall the output log that was generated when we clicked the button:

Mainactivity:dispatchtouchevent
Group_a:dispatchtouchevent
Group_a:onintercepttouchevent
Group_b:dispatchtouchevent
Group_b:onintercepttouchevent
View:dispatchtouchevent
View:ontouchevent

We find that passing through Mainactivity will eventually reach the contentview of the activity, which is the outermost linearlayou in the layout file we define.
What happened after that, what we observed through the log seemed to be: The event continues to pass down until the last button is reached, which is handled by Ontouchevent.
So, we are bold to guess: a "touch event" occurs, will step dispatchtouchevent, until the lowest view, and then through the ontouchevent processing.
This seems to make sense, but the only flaw is that the Onintercepttouchevent name reveals the way to intercept events, and it doesn't seem to get any play.

So, we simply open the ViewGroup in the source of Onintercepttouchevent:

    publicbooleanonInterceptTouchEvent(MotionEvent ev) {        returnfalse;    }

We found the source code very simple, the only notable is that the method has a Boolean return value, and the default return value is False.
Adhering to the consistent idea of "hand-linearlayou", we modified the onintercepttouchevent return value in our custom class to True. Then test again:

Mainactivity:dispatchtouchevent
Group_a:dispatchtouchevent
Group_a:onintercepttouchevent
Group_a:ontouchevent

We found that the log printing has changed, through the log we observed that: the event passed to Group_a no longer passed down, directly through the group_a ontouchevent processing.
This phenomenon is actually reasonable, it tells us: The return result of Onintercepttouchevent will determine whether the event is intercepted at the current view level. Returns true to intercept, otherwise continue delivery.
The result of Onintercepttouchevent's return can be found in the Dispatchtouchevent method in the ViewGroup class.
ViewGroup among the dispatchtouchevent source code is many, also very complex, we are difficult to read a thorough. But with some key code, we can see that it works as follows:
In ViewGroup, Dispatchtouchevent calls to the Onintercepttouchevent method and determines the next action by judging its return result:

  • If Onintercepttouchevent returns True, the Ontouchevent method is called to handle the touch event.
  • If Onintercepttouchevent returns FALSE, the event is distributed down the Child.dispatchtouchevent form.

By now, it seems that we have almost touched the entire distribution process of the event. But let's imagine a situation like this:
Xiao Ming's company received a new business and distributed it to the little king below. But the problem may be:
After receiving the notice, Xiao Wang found himself unable to finish. Or, Xiao Wang gives a plan, but his confidence in the program is not enough.
This problem should be solved, it is clear that Xiao Wang should "report the boss." The final treatment of this business may still have to be taken from you.

This corresponds to our program, how should it be implemented? We found that the Ontouchevent method also has a Boolean return value.
Now, we are trying to modify the return value of ontouchevent in our previously customized button class to a fixed return of false. Run the program test again:

Mainactivity:dispatchtouchevent
Group_a:dispatchtouchevent
Group_a:onintercepttouchevent
Group_b:dispatchtouchevent
Group_b:onintercepttouchevent
View:dispatchtouchevent
View:ontouchevent
Group_b:ontouchevent
Group_a:ontouchevent

We found that after the event was ontouchevent processed in the button class, it was sent back to the upper directory to continue processing.
From this we can know: The return value of ontouchevent is another kind of "interception", but the difference is that the interception event continues to pass down.
And here, is to indicate whether the event "I" is able to deal with it completely. If it does, it returns true, so the event ends after I have processed it. Otherwise, return false and let the parent view handle it.

Well, let's start with a summary of the process we've learned so far about the event distribution mechanism:

  • When a touch event occurs, it is first passed to the activity to which it belongs. Activity will be responsible for distributing the event downward.
  • The touch event will be passed down sequentially, until it is passed to the lowest view, and then processed.
  • ViewGroup The event is passed down, the return value of the onintercepttouchevent is passed to determine whether to intercept the event.
  • If the interception event is determined, then this series of touch events will be handled by the ViewGroup Ontouchevent method and no longer passed down
  • The return result of the ontouchevent determines whether the event needs to be uploaded back to the previous view after this processing.

OK, let's keep looking. We must have noticed and said so much, but our previous focus on event distribution is in the process of distributing events on the previous view to the lower view.
In other words, before we focused on analyzing ViewGroup's Dispatchtouchevent method, we said that the method would determine whether to intercept the event and decide whether to continue passing the event down.
When taking our example in this article, when the event is finally passed to the button class. It is not difficult to imagine that Dispatchtouchevent's work must have been different from before.
Because the button itself is just a view, there is no so-called child view. Also say, this time the incident you certainly have to deal with, then also distribute a what strength?

The best way to get the answer to this question is, of course, to open the source of the Dispatchtouchevent method in the view class, where we only intercept the parts of the code that we care about:

 if  ( Onfiltertoucheventforsecurity (event )) {//noinspec            tion simplifiableifstatement  listenerinfo li = mlistenerinfo; if  (Li! = null  && li.montouchlistener! = null  && (mviewflags & enabled_mask) = = ENABLED && Li.montouch  Listener.ontouch (this , event )) {result            = true ; } if  (!result && ontouchevent (event             ) {result = true ; }        }

As we can see, we first get a variable of type Listenerinfo. The type actually encapsulates the various types of listener. The first judgment is then opened:
If this object is not empty, Montouchlistener is not empty, and (Mviewflags & Enabled_mask) ==enabled, Montouchlistener is executed.
This one (Mviewflags & Enabled_mask) ==enabled is to determine whether the control state is enabled, which is certainly the default.
Montouchlistener look familiar, if we look at the source code, you are more familiar with, because we found that it is assigned by the following code:

    publicvoidsetOnTouchListener(OnTouchListener l) {        getListenerInfo().mOnTouchListener = l;    }

Looking at the code, we find that if Li.mOnTouchListener.onTouch (this, event) executes the result also true, then result will also be set to true.
Assuming that the execution result of the method returns False, then the above code will proceed, thus starting the second round of judgment, so the Ontouchevent method executes.

OK, for the code here, I think there are two points worth saying. First, we can first understand the following conclusions:

  • If we set a ontouchlistener for a view, then listener will execute before ontouchevent. While
  • If the Ontouch method of listener returns True, then Ontouchevent will no longer execute.

2nd, we see that for view: Assuming that the return value of Ontouchevent is False, Dispatchtouchevent also returns false.
This actually makes up the whole "ontouchevent return value can determine whether the event is returned" reason. This is because:
ViewGroup when distributing events through Child.dispatchtouchevent, the return value is passed to determine whether the child view has the ability to handle events.
If it returns to false, it continues to traverse the child view until it is traversed to a child view that has the ability to handle the event.
Without a sub-view of processing power, ViewGroup will resolve itself through ontouchevent.

Here we have actually got a good idea of the distribution mechanism for the entire Android event. But we will certainly think of a problem:
That is, in the case of a button, we usually set the Click event to listen to it in a setonclicklistener way.
But it is clear that the code we have studied so far has not seen anything related to it. In the view class, the rest of us have not seen the code, that is ontouchevent:

        if((viewflags & clickable) = = Clickable | |                (ViewFlags & long_clickable) = = long_clickable) | | (ViewFlags & context_clickable) = = context_clickable) {Switch(action) { CaseMOTIONEVENT.ACTION_UP:Booleanprepressed = (Mprivateflags & pflag_prepressed)! =0;if((Mprivateflags & pflag_pressed)! =0|| prepressed) {//Take focus if we don't have an it already and we should in                        //Touch mode.                        BooleanFocustaken =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 was a tap, so remove the Longpress checkRemovelongpresscallback ();//Only perform take click on actions if we were in the pressed state                            if(!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 =NewPerformClick (); }if(!post (Mperformclick))                                {PerformClick (); }                            }                        }

The above code is the reason why we are concerned, we see after a series of judgments, will go into a method called PerformClick call, open the source of the method:

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

Combining the above two pieces of code, we can draw the following conclusions:

  • Onclicklistener will be executed when the action is up in the Ontouchevent method.
  • However, note that the control is clickable (long press), and Monclicklistener is not empty.
The final summary and metaphor

Finally, we still take the example of "Xiao Ming Entrepreneurship" to summarize the knowledge we have learned about the distribution of events in Android.

  • The company (Activity) received a new business ( Touch event ).
  • The business will be the first to reach the company's highest level Xiao Ming hand ( top view).
  • Xiao Ming studied the following business, at this time can be divided into two kinds of situations:
    1, Xiao Ming thought this business is not very difficult, so decided to assign business to the department manager Xiao Wang (dispatch-event).
    2, Xiao Ming think this business is very important, decided to deal with their own (Intercept-event & Ontouchevent).
  • Assuming the business is assigned to the manager Xiao Wang, at this time Xiao Wang, like xiaoming, there are two options: the interception of their own processing or continue to lay down.
  • The business will eventually be assigned to the hands of an employee who is responsible for processing (ontouchevent).
  • But when the employee receives the task, he or she can decide if he or she can finish it,
    or need a superior audit, you can choose to return to the superior (Ontouchevent return false)
  • There may be many ways that an employee handles the task, such as a (ontouchlistener), B (ontouchevent), C (onclicklistener), and so on.
    (their order of precedence is a > B > C ....) )

Understanding the Android event distribution mechanism

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.