preface

Nice to meet you

This article is the third in the event distribution series.

In the previous two articles, Android Event distribution mechanism 1: How do events arrive in An Activity? Analyze the real starting point of event distribution: viewRootImpl, Activity is only one part of it; Android event distribution mechanism two: viewGroup and view on the event processing source parse viewGroup and view is how to distribute events.

The core content of event distribution is the distribution of events by viewGroups and views, which is the second article. The second article is a more in-depth analysis of the source code and lacks a higher perspective on the event distribution process. Based on the previous analysis, this article summarizes the workflow of event distribution to better understand how events are transmitted between different objects and methods.

review

Let’s review the overall process to better position our knowledge.

  1. The touch information is generated when the phone touches the screen and is sent to the View wroo TIMPL via IMS and WMS
  2. The viewRootImpl passes touch information to the View by calling the View’s dispatchPointerEvent method
  3. The View begins event dispatch by calling its dispatchTouchEvent method

The view in the figure refers to a control tree, which can be a viewGroup or a simple view. Because a viewGroup inherits from a View, a control tree can also be viewed as a view.

The workflow we’ll explore today starts with the View in the figure calling its own dispatchTouchEvent.

Main objects and methods

The object to which the event is distributed

This part of the content in the second chapter has a detailed analysis, here is a simple review.

A series of MotionEvent objects are generated when our phone touches the screen, and these objects are of different types depending on the touch. Details are as follows:

  • ACTION_DOWN: Press down the screen
  • ACTION_MOVE: When a finger slides across the screen, a series of MOVE events are generated
  • ACTION_UP: Lift your finger away from the screen,
  • ACTION_CANCEL: This type of event is generated when the event sequence is interrupted due to an exception
  • ACTION_POINTER_DOWN: This event is generated when a finger has already been pressed by another finger
  • ACTION_POINTER_UP: When multiple fingers are pressed at the same time, this event is generated when one finger is lifted

Method of event distribution

Event distribution belongs to a part of the control system, the main distribution object is viewGroup and View. There are three core methods: dispatchTouchEvent, onInterceptTouchEvent and onTouchEvent. So before we get into the distribution process, let’s introduce these three methods. CallBack interface contains dispatchTouchEvent and onTouchEvent methods. Activity and Dialog both implement Window.CallBack interface. So both implement the method. Because these three methods are often overridden in custom views, the following analysis, unless otherwise noted, is implemented using the default methods.

dispatchTouchEvent

This method is the core method of event distribution, and the logic of event distribution is implemented in this method. This method exists in the View class and is overridden by subclasses ViewGroup and other implementation classes such as DecorView.

Whether in a viewGroup or view, the main purpose of this method is to handle events. Returns true on success and false on failure, indicating that the event was not processed. Specific to the class, in the viewGroup related class, the main function of this method is to distribute the event to the viewGroup owned by the child view, if the child view does not process it itself; In the view’s related classes, the primary role of this method is to consume touch events.

onInterceptTouchEvent

This method exists only in the viewGroup and is called by the viewGroup when an event needs to be dispatched to a child view to check for interception. If it intercepts, it handles the event itself, and if it doesn’t, the child view’s dispatchTouchEvent method is called to distribute the event.

Method returns true to intercept the event, false to not intercept.

By default, this method intercepts only one special case of mouse-related operations; other cases require specific implementation classes to override intercepts.

onTouchEvent

This method, which is the primary method for consuming events, exists in the view and is not overridden by viewGroup default. Method returns true for consuming the event and false for not consuming the event.

When a viewGroup distributes an event, if none of its children consume the event, it calls its own onTouchEvent method to handle the event. In the dispatchTouchEvent method of a View, instead of calling onTouchEvent directly to consume the event, onTouchListener is called first to determine whether the event is consumed. If onTouchListener does not consume the event, onTouchEvent is called to handle the event.

The onClickListener and onLongClickListener we set for the View are called in the View’s dispatchTouchEvent method based on the specific touch.

Important rules

One important principle of event distribution is that a sequence of events for a touch point can only be consumed by a view unless an exception occurs such as being intercepted by a viewGroup. The code implementation is: a view that consumes a down event of the touch point sequence will continue to consume all subsequent events of the touch point sequence. Here’s an example:

When I press the screen with my finger, a Down event is generated, and only one view consumes the Down event, so any subsequent move event generated by my finger swiping the screen will consume that view and only that view. And when I lift the phone and press it again, a new Down event will be generated at this time, so I will look for the view that consumes the Down event again. So, event distribution is in a sequence of events.

Therefore, the following workflow refers to the distribution of down events, not ACTION_MOVE or ACTION_UP. Consuming the Down event means that all subsequent move and Up events will be handled by the view, so there is no distribution. But note that the event sequence can be interrupted by the onInterceptTouchEvent of the viewGroup. These are other cases.

Careful readers will also notice the inclusion of multi-touch in event distribution. In the case of multi-touch, ACTION_POINTER_DOWN and ACTION_DOWN have different distribution rules, which can be found in the second article. ACTION_POINTER_DOWN has made a few changes to the ACTION_DOWN distribution model, which will be explained later.

Workflow model

Workflow model is essentially the relationship between different control objects, viewGroup and View event distribution methods. Note that we are talking about default method implementations of viewGroups and Views, not overriding methods of other implementation classes such as DecorView.

Here is a piece of pseudocode to represent the relationship between the three event distribution methods (again, it is important to note that the event distribution model here distributes events of ACTION_DOWN type and is the default method, not overwritten) :

public boolean dispatchTouchEvent(MotionEvent event){
    
    // Determine whether to intercept first
    if (onInterceptTouchEvent()){
        // If the interceptor calls its own onTouchEvent method to determine whether to consume the event
        return onTouchEvent(event);
    }
    // Otherwise, call the distribution method of the child view to determine whether to handle the event
    if (childView.dispatchTouchEvent(event)){
        return true;
    }else{
        returnonTouchEvent(event); }}Copy the code

This code nicely illustrates the relationship between the three methods: When a viewGroup receives a touch event, it will call onInterceptTouchEvent to determine whether to intercept it. If it does, it will call its own onTouchEvent method to handle the event. Otherwise, the child view’s dispatchTouchEvent method is called to distribute the event. Since a subview can also be a viewGroup, this creates a recursion-like relationship.

Here I add simplified pseudocode for the view distribution logic:

public boolean dispatchTouchEvent(MotionEvent event){
    // Check if onTouchListener exists and return true
    if(mOnTouchListener! =null && mOnTouchListener.onTouch(event)){
        // Returns true on successful consumption
        return true;
    }else{
        // Otherwise call onTouchEvent to consume the event
        returnonTouchEvent(event); }}Copy the code

A view, unlike a viewGroup, does not need to distribute events, so there is no need to intercept them. The View checks to see if there is an onTouchListener and if the value returned is true. If so, it returns directly. Otherwise, the onTouchEvent method is called to handle the event.

Based on the above relationship, the following workflow flow chart can be obtained:

Here we draw two viewgroups to show class recursion. Just look at the middle one. Here we parse the graph:

  • viewGroup
    1. The viewGroup dispatchTouchEvent method receives an event message and calls onInterceptTouchEvent to determine whether to intercept the event
      • If it does, it calls its own onTouchEvent method
      • If not, the child view’s dispatchTouchEvent method is called
    2. The child view has no consumption event, so the onTouchEvent of the viewGroup itself is called
    3. The results of the above steps 1 and 2 are the results of the viewGroup dispatchTouchEvent method and are returned to the onTouchEvent of the upper layer
  • view
    1. The view dispatchTouchEvent by default calls onTouchEvent to handle events, returning true for consumption events and false for no consumption events
    2. The result of step 1 is the result of the dispatchTouchEvent method, which returns true on success and false on failure and passes to onTouchEvent at the next level

You can see that the entire workflow is a “U” structure that, without interception, looks for views that consume events one layer at a time. If the current view is not handling the event, then layer by layer you throw up and look for the viewGroup to handle.

The workflow model described above is not complete and there are other special cases that are not considered. A few special cases are discussed below:

The sequence of events is interrupted

We know that when a view receives a Down event, subsequent events from that touch point will be consumed by the view. However, a viewGroup can choke off the event stream in mid-stream, because every event that needs to be distributed to a child view needs to go through an intercepting method: onInterceptTouchEvent (of course, we don’t discuss the case of a child view setting not intercepting flags here). So what happens when the viewGroup cuts off the event stream? (Note that the move or UP event of a single-finger operation is intercepted by a viewGroup instead of a multi-finger operation.)

  1. When a viewGroup intercepts a child view’s move or Up event, it sends the current event to the child view as a Cancel event
  2. If the current sequence of events is not finished, those subsequent events are handed over to the viewGroup ouTouchEvent
  3. If either the viewGroup or view’s onTouchEvent returns false, this will cause the dispatchTouchEvent method of the entire control tree to return false
    • Following the principle that a sequence of events can consume only one view, if a view consumes a Down event but returns false in a subsequent move or Up event, the event will not be processed by the upper viewGroup, but will return false directly.
Multi-touch

All of the cases discussed above do not involve multi-touch. In the case of multi-touch, some special cases are added to the original event distribution process. Instead of drawing a picture, I will describe some special cases so that the reader can understand them.

By default, viewGroups support multi-touch distribution, but views do not support multi-touch, so you need to override the dispatchTouchEvent method to support multi-touch.

The multi-touch distribution rules are as follows:

When a viewGroup receives an ACTION_POINTER_DOWN event from another touch, another finger presses it to generate an ACTION_POINTER_DOWN event that is passed to the viewGroup:

  1. The viewGroup will distribute ACTION_POINTER_DOWN events as ACTION_DOWN
    • If the child view consumes the event, it is consistent with the process of single touch
    • If the child view does not consume the event, it is passed to the last view that received the Down event
  2. ViewGroup Two views receive different Down events, so the event sequence of one view is intercepted, and the viewGroup does not consume the intercepted event sequence. In other words, a viewGroup and its view cannot receive touch events at the same time.

Event distribution for the Activity

A careful reader will notice that the above workflow does not involve activities. Activity -> Window -> ViewGroup This is all due to the DecorView.

The DecorView overrides the dispatchTouchEvent method of the viewGroup. When a touch event is received, the DecorView first passes the touch object to the internal callBack object. Yes, the callBack object is an Activity. After joining the Activity, the distribution process is shown below:

The Activity inherits the Window.callback interface, so it also has the dispatchTouchEvent and onTouchEvent methods. A simple analysis of the image above:

  1. Once the activity receives the touch event, it distributes it directly to the viewGroup
  2. If the viewGroup dispatchTouchEvent method returns false, the Activity’s onTouchEvent is called to handle the event
  3. The results of steps 1 and 2 are the results of the activity’s dispatchTouchEvent method and are returned to the upper layer

The above process applies not only to activities but also to control systems such as Dialog that use DecorView and callback patterns.

The last

At this point, the main content of event distribution is explained. Combined with the previous two articles, it is believed that readers have a higher awareness of event distribution.

The paper come zhongjue shallow, and must know this to practice. The most important thing after learning knowledge is practice. The next article will take a brief look at how you can apply what you’ve learned about event distribution to real-world development.

Original is not easy, your praise is the biggest motivation for my creation, thank you for reading ~

Full text here, the original is not easy, feel help can like collection comments forward. I have no talent, any ideas welcome to comment area exchange correction. If need to reprint please comment section or private communication.

And welcome to my blog: Portal