Android event distribution mechanism three: event distribution workflow

Preface

Nice to meet you~

This article is the third in the event distribution series.

In the first two articles, Android event distribution mechanism 1: How does the event reach the activity? Analyzed the real starting point of event distribution: viewRootImpl, Activity is just one of the links; Android event distribution mechanism 2: viewGroup and view handling of events The source code analyzes how viewGroup and view distribute events.

The core content of event distribution is the distribution of events by viewGroup and view, which is the second article. The second article analyzes the source code in depth and lacks a higher perspective to examine the event distribution process. Based on the previous analysis, this article summarizes the entire workflow of event distribution to better understand how events are passed between different objects and methods.

review

Let's review the overall process first in order to better position our knowledge.

  1. Touch information is generated when the phone touches the screen, and sent to viewRootImpl through IMS and WMS
  2. viewRootImpl passes the touch information to the view by calling the dispatchPointerEvent method of the view
  3. The view starts event distribution by calling its own dispatchTouchEvent method

The view in the figure refers to a control tree, which can be a viewGroup or a simple view. Because viewGroup is inherited from view, a control tree can also be regarded as a view.

The workflow we are discussing today starts with the dispatchTouchEvent that the view in the figure calls itself.

Main objects and methods

Event dispatched object

This part of the content is analyzed in detail in the second chapter, here is a brief review.

When our mobile phone touches the screen, a series of MotionEvent objects will be generated. Depending on the touch situation, the types of these objects will be different. details as follows:

  • ACTION_DOWN: Indicates that the finger presses the screen
  • ACTION_MOVE: When the finger slides on the screen, a series of MOVE events will be generated
  • ACTION_UP: lift your finger, leave the screen,
  • ACTION_CANCEL: This type of event will be generated when the event sequence is interrupted in an abnormal situation
  • ACTION_POINTER_DOWN: When there is already a finger pressed, another finger press will generate this event
  • ACTION_POINTER_UP: When multiple fingers are pressed at the same time, lifting one of the fingers will generate the event

Event distribution method

Event distribution is part of the control system, and the main distribution objects are viewGroup and view. Of which there are three core dispatchTouchEventways: onInterceptTouchEvent, onTouchEvent, . So before talking about the distribution process, let's introduce these three methods. These three methods belong to the class view of the system, wherein the interface contains Window.CallBack dispatchTouchEventand onTouchEventmethods, Activity and Dialog have achieved Window.CallBack interface, implements the method. Because these three methods are often rewritten in custom views, the following analysis, unless otherwise specified, are all implemented in the default method.

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 class View, and the subclass ViewGroup and other implementation classes such as DecorView override this method.

Whether in viewGroup or view, the main function of this method is to handle events. It returns true if the processing is successful, and false if the processing fails, indicating that the event has not been processed. Specific to the class, in the viewGroup related class, the main function of this method is to distribute the event to the child views owned by the viewGroup, if the child view does not handle it, handle it by itself; in the view related class, the main function of this method is Consume touch events.

onInterceptTouchEvent

This method only exists in the viewGroup. When an event needs to be distributed to the child view, the viewGroup will call this method to check whether to intercept it. If you own the interception process, and will be called if the child does not block view of the dispatchTouchEventmethod of distributing the event.

The method returns true to intercept the event, and false to not intercept.

By default, this method only intercepts a special case of mouse-related operations, and other cases require specific implementation classes to override the interception.

onTouchEvent

This method is the main method of consuming events, and it exists in the view. ViewGroup does not override this method by default. The method returns true to indicate that the event is consumed, and false to indicate that the event is not consumed.

When viewGroup distributes events, if there is no child view to consume the event, it will call its own onTouchEvent method to handle the event. In the dispatchTouchEvent method of View, instead of directly calling the onTouchEvent method to consume the event, it first calls onTouchListener to determine whether to consume; if onTouchListener does not consume the event, then onTouchEvent is called to process the event.

The onClickListener and onLongClickListener that we set for the view are both called in the dispatchTouchEvent method of the view, according to the specific touch conditions.

Important rules

There is a very important principle of event distribution: an event sequence of a touch point can only be consumed by one view, unless an abnormal situation occurs such as being intercepted by the viewGroup . The specific code implementation is: a view that consumes a down event of a touch point event sequence will continue to consume all subsequent events of the touch point event sequence . Give a chestnut:

When my finger presses the screen, a down event is generated, and only one view consumes the down event. Then the move event generated by my finger sliding on the screen will and only consume this view. And when my phone is lifted and pressed again, a new down event will be generated at this time, so this time I will look for the view that consumes the down event again. Therefore, event distribution is based on the sequence of events .

Therefore, the following workflow refers to the distribution of down events , not the distribution of ACTION_MOVE or ACTION_UP. Because the down event is consumed, it means that the next move and up events will be processed by this view, and it doesn't matter if it is distributed. But at the same time, note that the event sequence can be interrupted by the onInterceptTouchEvent of the viewGroup. These belong to other situations.

Attentive readers will also find that multi-touch is included in event distribution. In the case of multi-touch, the distribution rules of ACTION_POINTER_DOWN and ACTION_DOWN are different. You can go to the second article for details. ACTION_POINTER_DOWN is slightly modified on the ACTION_DOWN distribution model, which will be analyzed in detail later.

Workflow model

The workflow model is essentially the relationship between different control objects, viewGroup and view event distribution methods. It should be noted that what is discussed here is the default method implementation of viewGroup and view, and does not involve overriding methods of other implementation classes such as DecorView.

The following pseudo code is used to represent the relationship between the three event distribution methods ( here again, the event type distributed by the event distribution model here is ACTION_DOWN and they are all the default methods, which is very important without rewriting ):

public boolean dispatchTouchEvent(MotionEvent event){
    
    
    
    // 先判断是否拦截
    if (onInterceptTouchEvent()){
    
    
        // 如果拦截调用自身的onTouchEvent方法判断是否消费事件
        return onTouchEvent(event);
    }
    // 否则调用子view的分发方法判断是否处理事件
    if (childView.dispatchTouchEvent(event)){
    
    
        return true;
    }else{
    
    
        return onTouchEvent(event);
    }
}

This code shows the very good relations between the three methods: When viewGroup receive a touch event, will go call the onInterceptTouchEventmethod to determine whether the interception, if the intercepted call your own onTouchEventmethod to handle events, or call the sub-view dispatchTouchEventapproach to Distribute events. Because the child view may also be a viewGroup, a recursive relationship is formed.

Here I will add a simplified pseudo code of view distribution logic:

public boolean dispatchTouchEvent(MotionEvent event){
    
    
    // 先判断是否存在onTouchListener且返回值为true
    if (mOnTouchListener!=null && mOnTouchListener.onTouch(event)){
    
    
        // 如果成功消费则返回true
        return true;
    }else{
    
    
        // 否则调用onTouchEvent消费事件
        return onTouchEvent(event);
    }
}

The difference between view and viewGroup is that it does not need to dispatch events, so there is no need to intercept events. The view first checks whether there is an onTouchListener and the return value is true, if it is true, it returns directly, otherwise it calls the onTouchEvent method to handle the event.

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

In order to show the class recursive relationship, two viewGroups are drawn here. Just look at the middle one. Here is an analysis of this picture:

  • viewGroup
    1. When the dispatchTouchEvent method of viewGroup receives the event message, it will first call onInterceptTouchEvent to determine whether to intercept the event
      • If intercepted, call its own onTouchEvent method
      • If not intercepted, call the dispatchTouchEvent method of the child view
    2. If the child view does not consume events, the onTouchEvent of the viewGroup itself will be called
    3. The processing result of the above steps 1 and 2 is the processing result of the dispatchTouchEvent method of the viewGroup, and is returned to the onTouchEvent processing of the upper layer
  • view
    1. The dispatchTouchEvent of the view will call onTouchEvent to handle the event by default, return true to indicate consumption event, and return false to indicate no consumption event
    2. The result of the first step is the processing result of the dispatchTouchEvent method. If it is successfully consumed, it will return true. If there is no consumption, it will return false and give it to the onTouchEvent of the upper layer for processing.

It can be seen that the entire workflow is a "U"-shaped structure. Without interception, the view of consumption events will be looked for layer by layer. And if the current view does not handle the event, then it will be thrown up layer by layer, looking for the processed viewGroup.

The above workflow model is not complete, and there are other special circumstances that have not been considered. Several special cases are discussed below:

Event sequence is interrupted

We know that when a view receives the down event, the next events of the touch point will be consumed by the view. However, the viewGroup can interrupt the event flow in the middle, because every event that needs to be distributed to the child view needs to go through the interception method: onInterceptTouchEvent(Of course, the case of setting the non-intercept flag for the child view is not discussed here). So when the viewGroup interrupts the event flow, what is the direction of the event? Refer to the figure below: ( Note that the multi-finger operation is not discussed here, only the move or up event of a single-finger operation is intercepted by the viewGroup )

  1. When viewGroup intercepts the move or up event of the child view, it will change the current event to a cancel event and send it to the child view
  2. If the current event sequence has not ended, those next events will be handed over to the viewGroup's ouTouchEvent for processing
  3. At this time, whether the onTouchEvent of the viewGroup or the view returns false, it will cause the dispatchTouchEvent method of the entire control tree to return false
    • Adhering to the principle that an event sequence can only be consumed by one view, if a view consumes a down event but returns false in the next move or up event, then this event will not be processed by the upper viewGroup, but will directly return false .
Multi-touch situation

All the situations discussed above do not include multi-touch situations. In the case of multi-touch, some special cases have been added to the original event distribution process. I will no longer draw pictures here, but describe some special situations, and readers can just understand them.

By default, viewGroup is touch-enabled distribution points, but the view does not support multi-touch, so you need to override the dispatchTouchEventmethod to support multi-touch.

The distribution rules for multi-touch are as follows:

When the viewGroup has received the down event of other touch points, another finger press generates the ACTION_POINTER_DOWN event and passes it to the viewGroup:

  1. viewGroup will distribute ACTION_POINTER_DOWN events in the ACTION_DOWN way
    • If the child view consumes the event, it is consistent with the single-touch process
    • If the child view does not consume the event, it will be handed over to the last view that received the down event for processing
  2. The two views of the viewGroup receive different down events, then the event sequence of one of the views is intercepted, and the viewGroup will not consume the intercepted event sequence. In other words, the viewGroup and its views cannot receive touch events at the same time.

Activity event distribution

Careful readers will find that the above workflow does not involve Activity. Event distribution in our impression is all Activity -> Window -> ViewGroup, so what is going on? All of this is the "cause" of DecorView.

DecorView viewGroup override the dispatchTouchEventmethod, after receiving a touch event, DecorView will first pass to the inside of the touch object callBack object. That's right, this callBack object is Activity. After joining the Activity link, the distribution process is shown in the following figure:

As a whole, there is not much difference from the previous process. Activity inherits the Window.CallBack interface, so there are dispatchTouchEvent and onTouchEvent methods. Make a simple analysis of the above picture:

  1. After the activity receives the touch event, it will directly distribute the touch event to the viewGroup
  2. If the dispatchTouchEvent method of the viewGroup returns false, then the onTouchEvent of the Activity will be called to handle the event
  3. The processing result of steps 1 and 2 is the processing result of the dispatchTouchEvent method of the activity and returned to the upper layer

The above process is not only applicable to Activity, but also applicable to control systems that use DecorView and callback modes such as Dialog.

At last

At this point, the main content of the event distribution is also explained. Combining the first two articles, I believe that readers have a higher awareness of event distribution.

It's always shallow on paper, and I absolutely know how to do it. The most important thing after learning knowledge is practice. The next article will briefly analyze how to use the learned event distribution knowledge and apply it to actual development.

Originality is not easy, your likes are the biggest motivation for my creation, thanks for reading ~

This is the full text. It is not easy to be original. If it is helpful, you can like it, bookmark it and forward it.
The author is very knowledgeable, and if you have any ideas, please feel free to communicate and correct in the comment section.
If you need to reprint, please comment section or private message exchange.

Also welcome to my personal blog: Portal

Guess you like

Origin blog.csdn.net/weixin_43766753/article/details/113092505