Implementation principle of Android event distribution mechanism

Event handling and sliding conflict resolution in Android are inseparable from the event distribution mechanism. The event flow in Android, that is, motionevent, will go through a process from distribution, interception to processing. That is, a process from dispatchtouchevent(), oninterceptevent() to ontouchevent(). Dispatchtouchevent() is responsible for the event distribution process. In dispatchtouchevent(), oninterceptevent() and ontouchevent() will be called. If oninterceptevent() returns true, the ontouchevent() method of the current view will be called. If it is not intercepted, The event will be distributed to the dispatchtouchevent () of the child view for the same operation. This article will lead you to analyze how Android distributes events from the perspective of source code.

The event distribution process in Android starts with the activity's dispatchtouchevent():

Getwindow(). Superdispatchtouchevent (EV) is called here. It can be seen that activity sends motionevent to window. Window is an abstract class and superdispatchtouchevent () is also an abstract method. Here, the subclass phonewindow of window is used.

It can be seen from here that the event event is passed to the decorview, that is, our top-level view. We continue to track:

Here, the dispatchtouchevent () method of the parent class is called, and decorview inherits from FrameLayout, which inherits ViewGroup. Therefore, the dispatchtouchevent () method of ViewGroup will be called here.

Therefore, the whole event flow starts from activity, passes to window, and finally to our view (ViewGroup also inherits from view), and view is the core stage of our whole event processing.

Let's take a look at the implementation of dispatchtouchevent () in ViewGroup:

This is a piece of code intercepted at the beginning of dispatchtouchevent(). Let's take a look. First, when we press view with our finger, we will call the resettouchstate() method. In resettouchstate():

We continue to track the cleartouchtargets () method:

In the cleartouchtargets () method, we finally assign mfirsttouchtarget to null. We continue to return to dispatchtouchevent (), and then execute the following code:

When view is pressed or mfirsttouchtarget= When null, we can know from the above that every time the view is pressed, that is, when the processing of the event flow is restarted, the mfirsttouchtarget will be set to null. Later, we will see when the mfirsttouchtarget is assigned.

From the disallowuntercept attribute, we can guess that it is used to judge whether to intercept. We know that our parent view can not intercept events by calling requestdisallowuntercepttuchevent (true) of the parent view. Let's take a look at the implementation of requestdisallowuntercepttuchevent() method first:

Here, the judgment processing is also done by setting the flag bit, so here is to change the mgroupflags flag, and then change the disallowintercept value in the dispatch touchevent() message to judge whether to intercept. When it is true, it is necessary to intercept. At this time, the onintercepttouchevent() interception judgment will be skipped and marked as not intercepted, that is, intercepted = false, Let's continue to look at the onintercepttouchevent() processing of ViewGroup:

That is, by default, only in action_ When down, the ViewGroup will be intercepted.

Let's move on:

This code will first traverse all child views through a loop, and finally call the dispatchtransformedtouchevent() method. Let's continue to look at the implementation of dispatchtransformedtouchevent():

This code is obvious. If child is not null, it will always call child. Dispatchtouchevent(); Otherwise, call super. Dispatchtouchevent();

If the child is not null, the event will be passed down. If the child view handles the event, that is, dispatchtransformedtouchevent() returns true. Continue to execute down to the addtouchtarget() method. Let's continue to look at the execution results of the addtouchtarget() method:

At this time, we find that mfirsttouchtarget appears again. At this time, we will assign a new value to mfirsttouchtarget, that is, mfirsttouchtarget is not null. In other words, if the event is consumed by the current view or sub view, then in the next action_ Move or action_ In the up event, mfirsttouchtarget is not null. However, if we inherit the ViewGroup and create an action in onintercepttuchevent()_ If the event is intercepted in move, the subsequent events will not be distributed and will be handled directly by the ViewGroup. We can get from the following code:

When there is a child view and the event is consumed by the child view, that is, in action_ In the down phase, mfirsttouchtarget will be assigned, that is, in the next action_ In the move event, because intercepted is true, action is_ After the cancel event is passed, you can see from dispatchtransformedtouchevent():

And finally assign the mfirsttouchtarget to next. At this time, mfirsttouchtarget is at the end of the touchtarget list, so mfirsttouchtarget will be assigned null, and the next event will not enter onintercepttuchevent(). It will also be directly handled by the view.

If we do not intercept the event, but leave it to the child view for processing, because the onintercepttouchevent() of ViewGroup will not intercept except action by default_ Events other than down, so subsequent events will continue to be handled by the child view. If there is a child view and the event is located in the internal area of the child view.

Therefore, whether intercepted or not, the event flow will be handled by dispatchtouchevent() in the view. Next, let's track the process of dispatchtouchevent() in the view:

When pressed, action_ When down, the view will stop internal scrolling. If the view is not covered or obscured, first judge whether mlistenerinfo is empty. Let's see where mlistenerinfo is initialized:

It can be seen here that mlistenerinfo is generally not null. We know that this code is called when we use it. When the view is added to the window, the following code will be called. It can also be seen from the comments:

From here, we know that mlistenerinfo is initialized at the beginning, so Li can't be null. Li.mtouchlistener= Null means that when the touchlistener is set, it is not null, and the view is enabled. Generally, the view is enabled. At this time, the ontouch () event will be called. When ontouch () returns true, the result will be assigned true. When result is true, ontouchevent () will not be called.

It can be seen from this that ontouch () takes precedence over ontouchevent (); When view sets touch listening and returns true, its ontouchevent () will be masked. Otherwise, ontouchevent() is called for processing.

Let's continue to look at event handling in ontouchevent():

First, when the view status is disabled, as long as the view is clickable or long_ Clickable or context_ Clickable will return true, while button is clickable by default, textview is not clickable by default, and view is generally not long by default_ Clickable.

Let's keep looking down:

If there is a proxy event, it will still return true

When view is clickable or long_ Clickable or context_ In the clickable state, if click listening is set when the finger is raised, performclick() will be called to trigger the click() event. This can be seen from the performclick () method:

From here, we can also see that the click event will be called in ontouchevent(). If the view sets ontouch() to listen and return true, the click event will also be shielded. However, we can continue to execute the click() event by calling performclick() of view in ontouch(), which depends on the requirements of our business.

From here, we can see that if the event is not processed by the current view or sub view, that is, false is returned, the event will be handed over to the outer view to continue processing until it is consumed.

If the event has not been processed, it will eventually be passed to ontouchevent() of the activity.

Here's a summary:

Event is a transfer process from activity - > window - > View (ViewGroup);

If the event is not intercepted halfway, it will be transmitted to the innermost view control;

If an event is intercepted by a certain layer, the event will not be passed down to the view for processing. If the view consumes events, the next events will also be handled by the view; If the view does not consume the event, the event will be handled by the outer view,... And finally called into ontouchevent() of the activity, unless a layer consumes the event;

An event can only be handled by one view;

Dispatchtouchevent() is always called, and is called first. Onintercepttouchevent() and ontouchevent() are called inside dispatchtouchevent();

The child view cannot interfere with the action of the ViewGroup_ Processing of down event;

The child view can control the parent view not to intercept events through requestdisallowintercepttouchevent (true) and skip the execution of onintercepttouchevent() method.

The above is the whole content of this article. I hope it will be helpful to your study, and I hope you can support programming tips.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>