preface

In fact, this belongs to the core knowledge of Android, before solving the sliding conflict and custom View have been understood, but there has been no systematic comb, here to comb carefully. Kind of a retrospective plus a consolidation series.

The body of the

We are all familiar with event passing, and I am sure we are all familiar with event passing, no matter how much we can say. The most common saying is that when an event is generated, it is first passed to the Activity, and then to a specific View. Today we will take a look at the event passing on the Activity.

Method three Musketeers

Here are 3 methods that must be old friends, so let’s briefly introduce them.

  • DispatchTouchEvent: Dispatches events, called when the event is passed to the Activity or ViewGroup.

Think about it:

  1. How events are distributed to the ViewGroup or the View, and who is passing this click event to me.

  2. When do I need to rewrite this method? When do I need to call its super method?

  3. What does this method return value representation mean, and does it affect event passing and handling?

  • OnInterceptTouchEvent: Intercepts events. You can use this method to intercept events when they are passed to a ViewGroup.

Think about it:

  1. If it is interception, when is it being intercepted and by whom?

  2. If the result is true, the event must be intercepted so that it is not passed down.

  3. Events can be DOWN, MOVE, and UP. Whether all events need to be intercepted?

  • OnTouchEvent: Handles the click event and is called when the current object needs to handle the event.

In fact, we are familiar with the above three methods, but some details sometimes we can only understand a little, that is, because of this, encounter some complex custom View, will not solve the problem, so we take the problem, to comb through.

Method of the Activity event

We’ll start with the event passing to the Activity directly here, and fill in the previous flow later.

First, we override methods in our Activity code. Only two methods can be overloaded:

An Activity cannot override onInterceptTouchEvent to intercept events.

Activity dispatches events

The first thing we need to know is that the system passes the click event to the Activity by calling the Activity’s dispatchTouchEvent method, not so much passing, but calling that method.

// This is the method of the Activity source code
// The argument here is the click event that the system passes to the Activity
public boolean dispatchTouchEvent(MotionEvent ev) {
    // This can not be analyzed
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        onUserInteraction();
    }
    // When this condition is true, the method is returned directly
    if (getWindow().superDispatchTouchEvent(ev)) {
        return true;
    }
    // If the above condition is false, call onTouchEvent
    return onTouchEvent(ev);
}
Copy the code

Let’s look at the getWindow().superdispatchTouchEvent () method:

// The Window class is an abstract class
public abstract boolean superDispatchTouchEvent(MotionEvent event);
Copy the code

We found the default unique implementation of the PhoneWindow class, which calls the following method:

/ / PhoneWindow class
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
    return mDecor.superDispatchTouchEvent(event);
}
Copy the code

One of the things you’ll find particularly familiar here is mDecor, which means DecorView. Look at this method in the DecorView class:

/ / DecorView class
public boolean superDispatchTouchEvent(MotionEvent event) {
    return super.dispatchTouchEvent(event);
}
Copy the code

The parent’s dispatchTouchEvent is called. Let’s see what happens:

//DecorView is a FrameLayout subclass
public class DecorView extends FrameLayout
Copy the code
// The ViewGroup dispatchTouchEvent method is called
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    if(mInputEventConsistencyVerifier ! =null) {
        mInputEventConsistencyVerifier.onTouchEvent(ev, 1); }... }Copy the code

I’m calling the ViewGroup distribution event method, and I’m actually passing the click event to the ViewGroup.

The event starts with Activity -> ViewGroup

In fact, from the above we can conclude that event passing is achieved by constantly calling the function.

That goes back to the Activity’s dispatchTouchEvent method:

// The Activity's dispatchTouchEvent method
public boolean dispatchTouchEvent(MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        onUserInteraction();
    }
    // This judgment will take a long time to return
    if (getWindow().superDispatchTouchEvent(ev)) {
        return true;
    }
    return onTouchEvent(ev);
}
Copy the code

The result of the judgment condition is not determined by the Activity code, it involves the judgment of all views below it, that is, when the getWindow().superdispatchTouchEvent () method is finished, the event has been passed. If you click on a button that has 10 layers wrapped around it, you must have distributed at least 10 layers before you can get the result, so this method can be time-consuming.

Chain of responsibility idea

In fact, this idea is the chain of responsibility idea, passing a click event layer by layer, starting from the Activity, when a layer of processing, the method can return, this call is very deep.

So this is an important idea, and one of the key things about it is the bottom-pocket idea, so for example, if you have a layer in the middle and it doesn’t process the consumption after it sends the event to the next layer, then that layer can process it by itself, like in the Activity method, The onTouchEvent method is called when getWindow().superDispatchTouchEvent returns false.

OnTouchEvent method

One thing we need to know is that the onTouchEvent method of this Activity is called under the condition that the View below it does not consume the event.

So that’s the bottom line. When none of the Activity’s siblings can consume the event, the Activity’s boss handles it, so if you overload the onTouchEvent method in your Activity, it doesn’t necessarily get called.

Intercepts events from the Activity

Now that we know the Activity’s dispatchTouchEvent distribution flow, we can do something like make the entire page unclickable.

// The Activity that needs to mask the click eventoverride fun dispatchTouchEvent(ev: MotionEvent?) :Boolean {
// return super.dispatchTouchEvent(ev)
        return true
    }
Copy the code

I don’t call the super.dispatchTouchEvent method directly here, so I don’t distribute the click event, so we usually write code must pay attention to the call of the super. XXX method, is not optional, to understand its principle.

Method return value

As the Activity is the leader in event distribution, the return values of its two methods don’t matter much anymore.

  • For the return value of dispatchTouchEvent, either true or false indicates that the event was dispatched, its return value is for its upper level, and true indicates that the event was consumed.

  • The same applies to the return value of onTouchEvent, indicating whether or not the event was consumed, but this return value is called from the dispatchTouchEvent method of its sibling Activity and has a different meaning.

conclusion

As for the process, I directly found a very classic picture from the Internet

This article is actually very simple, mainly on several core points, one is how events are distributed from Activity to control, one is the idea of responsibility chain, two core methods call order is determined and we want to manually handle click events in the Activity layer.