When it comes to event distribution mechanism, many people may be half-informed and muddled. We all know the three core methods of Dispatch, onInterupt, and onTouchEvent, and we probably know what they do. But I don’t know if you know the connection between these three methods and the principle of event distribution. Today, I will share the event distribution with you. As long as I follow my rhythm step by step, I will ensure that the students who know a little about it are enlightened and instantly get through the two veins of Ren And Governor.

I. Methods and objectives of event distribution

In the minds of many people, there are three methods in View and ViewGroup, so the target of event distribution is View and ViewGroup. I wrote a simple Viewgroup and View, then clicked on the View after running it, and finally clicked on the key locations of the event distribution. See the picture below:



In the figure above, the Activity’s dispatchTouchEvent method is entered first, which is probably the most overlooked. Do Activity, ViewGroup, and View all have these methods?

The answer is no, and we can test this conjecture in several ways. In an Activity, there are only dispatch and onTouchEvent, but not onInterupt. The same is true in a View. In a Viewgroup, there are three methods. It’s not that I didn’t want to type it out or didn’t execute the event, it’s that there’s no onInterupt in the Activity and View parent classes at all. I’m going to take a screenshot of an Activity that doesn’t have an onInterupt method, and I’m going to take a screenshot of a View that doesn’t have an onInterupt method.



So we can draw the following conclusions:

There’s no onIneruptTouchEvent in an Activity or a View, there’s no onIneruptTouchEvent in anything else. When you think about it, it’s understandable that an Activity, as the top layer, doesn’t need to intercept all events, while a View, as the bottom layer, has no downstream to intercept.



Second, the process of event distribution

As you know, there are three core methods of event distribution, and TO explore the connection between them, I have logged all of them here.



We’ll start with the Activity’s dispatchTouchEvent method, which is the core distribution method.



As you can see, in the Activity we’re calling the superDispatchTouchEvent method for the Window, and that Window is actually an abstract class, and there’s only one instance of that class called PhoneWindow, so let’s look at the methods in PhoneWindow



Note that the PhoneWindow method calls the superDispatchTouchEvent method in the DecorView



In the DecorView, this method calls the dispatchTouchEvent method of its parent class. Who is the parent class of the DecorView? FrameLayout, of course, which is the outermost ViewGroup. So let’s go ahead and look at the dispatchTouchEvent method of the ViewGroup. The code is too complicated, so I’ll just cut the most important part of it and analyze it.



We see that onInterceptTouchEvent is explicitly called in dispatchTouchEvent, This explains why the onInterceptTouchEvent method in the ViewGroup is second only to the dispatchTouchEvent execution. Let’s move on to the next key piece of code:



The first call buildTouchDispatchChildList to a sort all of the view



BuildTouchDispatchChildList is ultimately call to buildOrderdChildList method, can be seen from the above code, the method is to do only one thing, that is the view for all to order according to the Z axis. Just to clarify, the z-axis is really the three-dimensional direction facing the user. The larger the Z value is, the more it goes to the bottom, which perfectly explains why events are passed in from the outermost ViewGroup. Note that the View currently being compared is not only in the click area, but all views on the screen will be included in the comparison.

After comparison, we can see above, the following calls another core method called isTransformedTouchPointInView, we go in to see this method.



The implementation of this method is very simple, passed in the click of x, Y coordinates, judge whether the current incoming view in the coordinate, through a cycle to traverse one by one, the final is the key view in the coordinate.

At this point, you have the View from the outside to the inside, one by one. Now it’s time to handle the actual distribution process:



We can see, the execution of the current container dispatchTransformedTouchEvent method, we go in to see:



As you can see, this method calls the dispatchTouchEvent of the child View. If the child View continues to be a ViewGroup, the above code will still be used. If the child View is not a ViewGroup, we can also look at the relevant code:



See, in the dispatchTouchEvent of a normal View, if the onTouchListener method is not overwritten and returns true, it will be executed in the onTouchEvent of the current View. Of course, if the onTouchEvent in the subclass does not return true, the onTouchEvent in its ViewGroup will also be executed. There is a responsibility chain mode involved here, the specific code is as follows



Here we can see that we loop through all views asking whether to handle the event, and if the child View returns false, the loop continues to call the parent View’s onTouchEvent. If dispatchTransFormedTouchEvent returned to the true, is also dealt with the incident, then will go to the following code:



We can see that if it is processed, it will break. This break represents the end of the long event distribution and will not continue distribution.



Come and smash the egg!

Note that the last two dots in my dot list are for ACTION_UP. I wonder why there are a bunch of dots for ACTION_DOWN and only two dots for ACTION_UP. It doesn’t seem to have been passed down at all, but just passed into the Activity. If you find it, you’ve been watching carefully, and I’ll give you the answer.



First of all, if no processing in the View onTouchEvent (), which returns false setTargetAccessibilityFocus method is executed to the MotionEvent when set to false, will disqualify the View of the incident response.

Next time another event is sent to the View, it will first determine whether the current View is still qualified. Since the qualification has just been cancelled, the onTouchEvent of the View will not be executed.



In the distribution of the first to obtain whether the current View is qualified, if not, directly skip. The consequence of skipping is very serious. If the View is not added to the list array that matches the coordinates, it is equivalent to waiting for the black room to receive the following events.



conclusion

So you can see that we can string this together, so let’s summarize.



First, the Activity’s dispatchTouchEvent calls the PhoneWindow superDispatchTouchEvent method, PhoneWindow calls the superDispatchTouchEvent method of a DecorView, which is the outermost ViewGroup, and goes to the onInteruptTouchEvent method of that ViewGroup, If true the dispatchTouchEvent method is called, otherwise the dispatchTouchEvent method at the next level is called, the View method at the next level is called, onTouchEvent method is called, if onTouch returns true the dispatchTouchEvent method is called, Otherwise, call the onTouchEvent method of the previous level, and so on. If you don’t understand it, you can read it again from the beginning and read it several times. If there are any mistakes mentioned above, you are welcome to raise them and make progress together.