Android event distribution mechanism 1: How does the event reach the activity?

Does event distribution really start from Activity?

Preface

Nice to meet you~

Event distribution, a common topic in android. I went to interview a company a while ago. There was a written test in him that asked about the process of event distribution. The correct answer is to choose: Activity->window->view. We all know the basic process is to start distribution from Activity.

After I chose, I started to think about how the event reached the Activity? Readers who have understood the window mechanism will know that event distribution is also a part of the window mechanism, and Activity does not belong to the window mechanism, so touch events should start from Window, how can they start from Activity?

With these questions in mind, I re-learned event distribution, combined with the previous window mechanism content, and gained a new understanding of event distribution. This article is to answer the question of how the event reaches the Activity.

Do you think I am going to talk about the source code and the bottom layer of the system? No, no, no, this article does not cover these. What we want to explore is that after a touch message is generated from the bottom of the system, it reaches the Activity step by step for distribution. The logic of the bottom of the system is beyond the scope of this article.

This article is the beginning of the author's android touch event series. The main content is to analyze the path of touch event delivery. It will not be entangled with the source code and the bottom layer, but the general process of the source of the touch event is presented, which facilitates a more complete understanding of the event distribution system.

Management unit: window

Android's view management is based on windows, and each window corresponds to a view tree. The management here involves the drawing of the view and event distribution. The Window mechanism not only manages the display of the view, but is also responsible for the event distribution of the view. Regarding the nature of the window, you can read another article on the window mechanism of the author . To study the source of event distribution, you must have a certain understanding of the window mechanism.

Therefore, we must first understand a concept: view tree.

Our application layout is generally nested with multiple layers of viewGroup and view, as shown below:

image

And their corresponding structural relationship is shown in the figure below

image

At this point, we can call the layout a view tree with a LinearLayout as the root. LinearLayout can directly access FrameLayout and RelativeLayout, because they are all child views of LinearLayout, and the same RelativeLayout can directly access Button.

Each view tree has a root called ViewRootImpl , which is responsible for managing the drawing and event distribution of the entire view tree.

Our application interface generally has multiple view trees, our activity layout is a view tree, the floating window of other applications is also a view tree, the dialog interface is also a view tree, the view we add using windowManager is also a view tree, etc. . The simplest view tree can have only one view.

View drawing and event distribution in android are based on the view tree. Each view tree is a window . The system service WindowManagerService, the display of the management interface is based on the window, which can also be said to be based on the view tree. The view tree is managed by viewRootImpl, so it can be said that wms (short for WindowManagerService) manages viewRootImpl. As shown below:

window mechanism

  • Wms runs in the system service process and is responsible for managing all application windows. The communication between the application and wms must be cross-process communication through Binder.
  • Each viewRootImpl has a corresponding windowState in wms, and wms can find the corresponding viewRootImpl through windowState for management.

An important reason for understanding the window mechanism is that event distribution is not driven by Activity, but by system service driven viewRootImpl to distribute . It can even be said that from the perspective of the framework layer, it has nothing to do with Activity. This will help us understand the nature of event distribution.

So how does the touch information reach viewRootImpl step by step? Why is viewRootImpl the starting point of event distribution? How does viewRootImpl distribute the touch information? This is what we will discuss next.

How does the touch information reach viewRootImpl?

What we all know is that when our fingers touch the screen, touch information is generated. This touch information is generated by the hardware of the screen, acquired by the underlying driver of the system, and given to the input system service of Android: InputManagerService, which is IMS.

IMS will process this touch information, find the window to be distributed through WMS, and then send it to the corresponding viewRootImpl. Therefore, it is not WMS that sends touch information, but WMS provides window-related information.

This part involves the logic of the bottom of the system and is not the focus of this article. Interested readers are recommended to read the article Input System-Event Processing Whole Process of the gityuan blogger . I will not explain it here. The general process is as follows:

How did the event arrive at viewRootImpl

When viewRootImpl receives touch information, it is also the beginning of the application process event distribution.

How does viewRootImpl distribute events?

As we mentioned earlier, viewRootImpl manages a view tree. The outermost layer of the view tree is viewGroup, and viewGroup inherits from view. Therefore, the entire view tree can be seen as a view from the outside. After viewRootImpl receives the touch information, it is processed, encapsulated into a MotionEvent object and sent to the view managed by it, and the view itself distributes it.

As we mentioned earlier, the root node of the view tree can be a viewGroup or a separate view. Therefore, there are two different ways of dispatching here: directly processing the view or dispatching the event to the viewGroup. viewGroup inherited from view, view, there is a method used to distribute event: dispatchTouchEvent. Subclasses can override this method to implement their own distribution logic, and ViewGroup overrides this method.

Our application layout interface or dialog interface layout, the top viewGroup is DecorView, and therefore calls DecorView the dispatchTouchEventmethod for distribution. DecorView rewrites this method, the logic is relatively simple, only made a judgment:

DecorView.java api29
public boolean dispatchTouchEvent(MotionEvent ev) {
    
    
    final Window.Callback cb = mWindow.getCallback();
    return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
            ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
}
  1. If the window callBack object is not empty, call the dispatch method of the callBack object to dispatch
  2. If the window callBack object is empty, call the event distribution method of the parent class ViewGroup for distribution

The windowCallBack here is an interface, which contains some callback methods for window changes, including the dispatchTouchEventevent distribution method.

Activity implements the Window.CallBack interface, and when creating the layout, set itself to DecorView, so in the layout interface of Activity, DecorView will distribute events to Activity for processing. Similarly, in the Dialog layout interface, it will be distributed to the Dialog that implements the callBack interface.

If the top-level viewGroup is not DecorView, then the dispatchTouchEventmethod that calls the corresponding view is distributed. For example, the top view is a Button, then Button will directly call the dispatchTouchEventmethod; if the top-level viewGroup subclass does not override dispatchTouchEventmethod, then calls the default ViewGroup direct dispatchTouchEventmethods.

The overall process is as follows:

ViewRootImpl's distribution process of events

  1. viewRootImpl calls direct view of the management of the dispatchTouchEventmethod, according to the specific type of view, call the specific methods.
  2. The root view of the view tree may be a view or a viewGroup. The view directly handles events and the viewGroup distributes them.
  3. DecorView rewrite dispatchTouchEventmethod will first determine whether there is callBack, method callBack priority call, which is to transfer the event to the Activity.
  4. Other viewGroup subclasses will dispatch events according to their own logic.

Therefore, the touch event must start from Activity? No, Activity is just one of the cases. Only the view tree that Activity is responsible for will definitely reach the activity, while other windows will not pass through the activity. The touch event starts from viewRootImpl, not Activity.

Distribution of events by controls

At this point, we know that the touch event is first sent to viewRootImpl, and then viewRootImpl calls the method of the view it manages to distribute the event. According to the normal process, the view will be distributed down according to the control tree. But the event went to activity and dialog because of the existence of the "traitor" DecorView.

As mentioned earlier, DecorView is very different from other viewGroups. It has a windowCallBack, which will send touch events to callBack first, causing touch events to leave the control tree. So, how do these callBacks handle touch events? How do touch events go back to the control tree for distribution again?

Before understanding the specific distribution, you need to understand a class: PhoneWindow.

PhoneWindow inherits from the abstract class Window, but it is not a window itself, but a window function auxiliary class. We know that a view tree, or control tree, is a window. PhoneWindow maintains a control tree and some window parameters. The root view of this control tree is DecorView. The relationship between them and Activity is as follows:

phonewindow

Our Activity manages this control tree by directly holding an instance of PhoneWindow. DecorView can be considered as an interface template, and its layout is roughly as follows:

decorView

Our Activity layout is added to the content bar and is part of the DecorView control tree. In this way, Activity can indirectly manage its own interface through PhoneWindow, and host all window-related operations to PhoneWindow, reducing its burden.

PhoneWindow is not exclusive to Activity. Others such as Dialog also create a PhoneWindow by themselves. PhoneWindow is just an auxiliary class for window functions to help controls better create and manage interfaces.

As mentioned earlier, after DecorView receives the event, it will call the windowCallBack method for event distribution. Let’s take a look at how Activity is distributed:

Activity

We first see Activity's implementation of the callBack interface method:

Activity.java api29
public boolean dispatchTouchEvent(MotionEvent ev) {
    
    
    // down事件,回调onUserInteraction方法
    // 这个方法是个空实现,给开发者去重写
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
    
    
        onUserInteraction();
    }
    // getWindow返回的就是PhoneWindow实例
    // 直接调用PhoneWindow的方法
    if (getWindow().superDispatchTouchEvent(ev)) {
    
    
        return true;
    }
    // 如果前面分发过程中事件没有被处理,那么调用Activity自身的方法对事件进行处理
    return onTouchEvent(ev);
}

You can see that Activity's distribution logic for events is relatively simple, and directly call the PhoneWindow method for distribution. If the event is not processed, then handle the event yourself. Next, look at how PhoneWindow handles:

PhoneWindow.java api29
public boolean superDispatchTouchEvent(MotionEvent event) {
    
    
    return mDecor.superDispatchTouchEvent(event);
}

The mDecor here is the DecorView maintained by PhoneWindow. It is simple and rude, and directly calls the DecorView method for distribution. See the DecorView method:

DecorView.java api29
public boolean superDispatchTouchEvent(MotionEvent event) {
    
    
    return super.dispatchTouchEvent(event);
}

Good guys, DecorView doesn't do any processing for the event, and directly calls the method of the parent class to distribute it. DecorView inherited from FrameLayout, but did not rewrite FrameLayout dispatchTouchEventmethod, so the call is a method viewGroup class. So here, the event is handed over to the viewGroup to be distributed to the control tree.

Let’s review: DecorView is handed over to Activity for processing, Activity is directly handed over to PhoneWindow for processing, PhoneWindow is directly handed over to its internal DecorView for processing, while DecorView directly calls the method of the parent class ViewGroup for distribution, and ViewGroup will be distributed according to specific logic Interested child controls in the entire control tree. Regarding how ViewGroup distributes content, I will continue to analyze it in subsequent articles.

Starting from DecorView, making a circle, and returning to the control tree for distribution. Next look at how Dialog is distributed:

Dialog

Dialog seen directly in diapatchTouchEventthe code:

Dialog.java api29
public boolean dispatchTouchEvent(@NonNull MotionEvent ev) {
    
    
    if (mWindow.superDispatchTouchEvent(ev)) {
    
    
        return true;
    }
    return onTouchEvent(ev);
}

The mWindow here is the PhoneWindow instance maintained inside the Dialog. The following logic is the same as the Activity process, so I won’t repeat it here.

And if you do not use DecorView as a template window, the process will be inconsistent with the above, such as PopupWindow:

PopupWindow

The root View of PopupWindow is PopupDecorView, not DecorView. Although his name has DecorView, it has nothing to do with DecorView. It is directly inherited from FrameLayout. We see his event distribution method:

PopupWindow.java api29
public boolean dispatchTouchEvent(MotionEvent ev) {
    
    
    if (mTouchInterceptor != null && mTouchInterceptor.onTouch(this, ev)) {
    
    
        return true;
    }
    return super.dispatchTouchEvent(ev);
}

mTouchInterceptorIt is an interceptor, we can manually set the interceptor to PopupWindow. The time will be given priority to the interceptor for processing. If there is no interceptor or the interceptor does not consume the event, it will be handed over to the viewGroup for distribution.

to sum up

Finally, we review the entire process:

Overall process

  1. After IMS receives the event from the bottom of the system, it will get the window information from WMS and send the event information to the corresponding viewRootImpl
  2. viewRootImpl receives the event information, encapsulates it into a motionEvent object, and sends it to the managed view
  3. View will distribute the event according to its own type or handle it by itself
  4. The top-level viewGroup is generally DecorView, and DecorView will choose to call callBack or call the method of the parent class ViewGroup according to its own callBack situation
  5. Regardless of the type of the top-level viewGroup, it will eventually reach the ViewGroup to distribute the event.

At this point, although the "destiny" of the touch event is still unclear, his "coming dragon" is already very clear.

The main content of this article is about the source of the event, but the source of the event distribution is far from simple. The details of the source code have a lot of content worth learning, but this article just extracts the overall process. For other content about the bottom of the system, I recommend a series of books for interested readers: "In-depth understanding of androidⅠⅡⅢ".

The next article will focus on analyzing how viewGroup distributes events to its child views accurately.

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/112714297