I’ve covered a lot of knowledge about View drawing, so at least 2D drawing is not a problem, and most of the requirements are met, but there are still a lot of knowledge about View, such as: Paint to make the drawing cool, animation to make the View move, touch events to interact with the user and so on. This time, WE will take a brief look at something closely related to interaction – the principle of event distribution.

The final station of the magic train is the event distribution, please bring good equipment, ready to embark.

Note: all source code analysis in this article is based on API23(Android 6.0). Due to many changes in Android source code, it may be different from previous versions, but the basic flow is the same.

Why is there an event distribution mechanism?

Android has a tree View structure, so views may overlap, so when we click on a place where there are multiple views that can respond, who should we give the click event to? To solve this problem, there is an event distribution mechanism.

When a finger clicks on View1, the following ViewGroupA, RootView, etc., can also respond. In order to determine which View should handle the click event, event distribution mechanism is needed to help.

View structure:

Our View is a tree structure. The structure of the example View in the previous question is roughly as follows:

Layout file:

<com.gcssloop.touchevent.test.RootView
	xmlns:android="http://schemas.android.com/apk/res/android"
	xmlns:tools="http://schemas.android.com/tools"
	android:layout_width="match_parent"
	android:layout_height="300dp"
	android:background="#4E5268"
	android:layout_margin="20dp"
	tools:context="com.gcssloop.touchevent.MainActivity">

	<com.gcssloop.touchevent.test.ViewGroupA
		android:background="#95C3FA"
		android:layout_width="200dp"
		android:layout_height="200dp">

		<com.gcssloop.touchevent.test.View1
			android:background="#BDDA66"
			android:layout_width="130dp"
			android:layout_height="130dp"/>

	</com.gcssloop.touchevent.test.ViewGroupA>

	<com.gcssloop.touchevent.test.View2
		android:layout_alignParentRight="true"
		android:background="#BDDA66"
		android:layout_width="80dp"
		android:layout_height="80dp"/>

</com.gcssloop.touchevent.test.RootView>
Copy the code

The View structure:

You can see that there are two things in the View structure that we didn’t define in the Layout file: PhoneWindow and DecorView.

If you look carefully at the layout file above, you will find a problem. The size of the View(Group) at the top of the layout file does not fill the parent form, leaving a large number of blank areas. Since the screen of our mobile phone is not transparent, these blank areas must display something. So what should be displayed?

As any android developer knows, the part of the screen that isn’t covered by a View shows the color of the theme. The top title bar is not in the layout file. Where is the title bar displayed?

You guessed it, the theme color and the title bar are displayed in the DecorView.

Now that you know what a DecorView does, what does PhoneWindow do?

To understand what PhoneWindow is all about, check out the official description:

Abstract base class for a top-level window look and behavior policy. An instance of this class should be used as the top-level view added to the window manager. It provides standard UI policies such as a background, title area, default key processing, etc.

In simple terms, the Window is an abstract class, is that all the View at the top of the container, and View the appearance and behavior of his pipe, whether it’s background, according to the title bar or event processing is his management category, it is like the View world body (although that tube appears to be a lot of, but no real power, as an abstract class cannot be used directly).

PhoneWindow, as the only child of Windows (the only implementation class), is naturally the king of the View world. PhoneWindow has a lot of power, but it is not very useful to us because the emperor usually hides in the palace. Although you can occasionally meet PhoneWindow in a special way, it is difficult to fully direct PhoneWindow to work for you.

A DecorView is an internal class of PhoneWindow that serves as a small eunuch that follows PhoneWindow and does its own work as well as passing messages. The PhoneWindow directive is passed to the following View through the DecorView, and the following View’s information is passed back to the PhoneWindow through the DecorView.

Event distribution, interception and consumption

The following table omits PhoneWidow and DecorView.

√ indicates that the method exists.

X means there is no such method.

type Relevant methods Activity ViewGroup View
Dispatching events dispatchTouchEvent Square root Square root Square root
Events to intercept onInterceptTouchEvent X Square root X
The event consumer onTouchEvent Square root Square root Square root

All three methods have a Boolean return value that controls the flow of event delivery by returning true and false.

As you can see from the table above, activities and Views do not block events. This is because:

As the Activity is the original event distributor, if the Activity intercepts events, the entire screen will be unable to respond to the event, which is definitely not the desired effect.

The View is at the very end of event delivery and either consumes the event or does not process it and sends it back. There is no need for event interception.

Event Distribution Process

Earlier we learned that our View is a tree structure, and based on this structure, our events can be distributed in an orderly manner.

Event collection is passed to the Activity first, and then down, as follows:

Activity -> PhoneWindow -> DecorView -> ViewGroup -> ... -> View
Copy the code

This event distribution mechanism is very logical, but do you notice a problem? What if it’s finally distributed to the View, what if the View doesn’t handle the event either, just letting the event go to waste?

If no View consumes the event, the event is passed back to the Activity in the opposite direction. If the Activity does not process the event, the event is discarded:

Activity <- PhoneWindow <- DecorView <- ViewGroup <- ... <- View
Copy the code

See here, I can not help but slightly a frown, this thing how looks so familiar? If I can handle it, I will intercept it and do it myself. If I can’t handle it or I am not sure, I will hand it to the next object in the responsibility chain.

This design is very delicate, the upper View can directly intercept the event, processing itself, or can first ask (distributed to) the child View, if the child View needs to be handed over to the child View, if the child View does not need to continue to the upper View. Not only ensure the order of the event, but also very flexible. When I first figured out this logic, I almost wanted to cheer when I saw such a clever design.

In fact, about the event passing mechanism, Wu Xiaolong’s Android event passing mechanism analysis article metaphor is very interesting, this article will also use some of them.

Start with a few characters:

Activity – Company boss

RootView – Project Manager

ViewGroupA – Technical team leader

View1 – Coder Xiao Wang (the only coder in the company)

View2 – Walk-on passer-by a, ignore it

PS: Since PhoneWindow and DecorView cannot be manipulated directly, all of the following examples omit PhoneWindow and DecorView.

1. Click on the View1 area but there is no View consumption event

If none of the views consume events after a finger click in the View1 area, you should see a complete event distribution process that looks like this:

The direction of the red arrow indicates the direction of the event distribution.

The direction of the green arrow indicates the direction of the event return.

Note: the diagram above shows that the distribution process is only a schematic process and does not represent the actual situation. If the actual situation is drawn, it will lead to a very complicated and confusing flow chart. After a long time of struggle, I made a difficult decision to adopt such a simplified process.

There are some unreasonable contents in the above process, please accept them selectively.

  1. When the event returnsdispatchTouchEventThat points directly to the parent ViewonTouchEventThis part doesn’t make sense, it’s actually just given to the parent ViewdispatchTouchEventA false return value that the parent View calls its ownonTouchEvent.
  2. ViewGroup is based ononInterceptTouchEventTo determine that the child View is calleddispatchTouchEventOr within itselfonTouchEvent, does not hand the call toonInterceptTouchEvent.
  3. The pseudo-code for the event distribution mechanism of the ViewGroup is shown below, showing the order of calls.
public boolean dispatchTouchEvent(MotionEvent ev) { boolean result = false; // Default is no consumption if (! OnInterceptTouchEvent (ev)) {result = child.dispatchTouchEvent(ev); } if (! Result) {// If the event is not consumed, ask itself onTouchEvent result = onTouchEvent(ev); } return result; }Copy the code

Testing:

Situation: Boss: I think the company’s business is not good recently, we are going to develop the e-commerce business, how about doing taobao before next week to try it out?

Event sequence, the boss (MainActivity) to do Taobao, this event through each department (ViewGroup) layer by layer down, to the bottom of the time, code farmer Wang (View1) found that can not do, so the message layer by layer back to the boss there.

You can see that the whole event route is very orderly. We start the Activity and pass it back to the Activity (we don’t have information for Phone Window and DecorView because we can’t manipulate them).

Manager, I am going to develop e-commerce business and make a Taobao before next week. RootView [manager]: dispatchTouchEvent call technology department, boss wants to do Taobao, online next week. RootView [manager]: onInterceptTouchEvent (Boss may be crazy, but I'm not doing it) ViewGroupA [group leader]: dispatchTouchEvent boss want to do Taobao, next week online? View1: dispatchTouchEvent (dispatchTouchEvent, dispatchTouchEvent) View1: onTouchEvent ViewGroupA [group leader]: onTouchEvent Xiao Wang said can not do. RootView [manager]: onTouchEvent reports to boss, tech says can't do it. MainActivity [boss]: You can't even do onTouchEvent. What are you doing?Copy the code

2. Click the View1 area and the event is consumed by View1

If the event is consumed by View1 then the event will be sent back to tell the upper View that I’ve resolved the event, and the upper View doesn’t have to respond anymore.

Note: the event return path in this diagram is the correct path.

Testing:

Boss: I don’t think our app button is pretty. Make it shiny and make people want to click it.

Event sequence, the boss (MainActivity) to change the interface, this event through each department (ViewGroup) layer by layer down, to the bottom of the time, code farmer Wang (View1) on the button to add a light (why is wang? Because the company has no designers).

As you can see, once the event is consumed, it means the end of message passing. The upper View knows that the event has been consumed and no longer processes it.

MainActivity [boss]: dispatchTouchEvent make the button nice, shiny, give people a desire to click. RootView [manager]: dispatchTouchEvent Technical department, boss said the button is not nice, need to add a light. RootView [manager]: onInterceptTouchEvent ViewGroupA [Group leader]: dispatchTouchEvent Adds a light to the button. ViewGroupA: onInterceptTouchEvent View1: dispatchTouchEvent add a light. View1: onTouchEvent is done.Copy the code

Add a light:

3. Click the View1 area but the event is blocked by ViewGroupA

The upper View has the right to intercept events without passing them to the lower View. For example, when a ListView slides, it does not pass events to the lower View.

Note: As you can see, if the upper level intercepts the event, the lower level View will not receive the event information.

Testing:

Situation: Boss: Report on the progress of the project.

The boss (MainActivity) needs to know the progress of the project. This event is passed down layer by layer through each department (ViewGroup). When it is transmitted to the technical group leader (ViewGroupA), the leader (ViewGroupA) can report the task. There is no need to tell the code farmer (View1).

MainActivity [boss]: dispatchTouchEvent how far is the project now? RootView [Manager]: dispatchTouchEvent Technology Department, are you almost finished with your app? RootView: onInterceptTouchEvent ViewGroupA: dispatchTouchEvent Project progress? ViewGroupA: onInterceptTouchEvent: onTouchEvent is being tested and will be finished tomorrowCopy the code

Other situations

The event distribution mechanism is designed for a variety of situations, which are not listed here, but the following principles should be kept in mind.

  • 1. If the event is consumed, it means that the transmission of event information is terminated.
  • 2. If the event is never consumed, it is eventually passed to the Activity, and if it is not needed, it is discarded.
  • 3. Determine whether an event is consumed based on the return value, not whether you use the event.

Download the source code for the test

conclusion

View event distribution mechanism is actually a very classic chain of responsibility model, if you understand the chain of responsibility model, then event distribution is not a problem for you, if you do not understand the chain of responsibility model, just take this opportunity to learn.

Chain of Responsibility mode:

When more than one object can handle the same request, chain the objects together and pass the request along the chain until an object handles it.

Although the principle of event distribution mechanism in Android is very simple, but because the actual scene is very complex, once it becomes very troublesome in a specific scene, and this article only gives you a brief understanding of the event distribution mechanism, more detailed content and specific handling of some special cases will be explained in the subsequent article.

Sequel:

  • Android Custom control advanced 01- Custom control development routines and processes
  • Android custom controls advanced 02-Canvas drawing graphics
  • Android custom controls advanced 03-Canvas Canvas operation
  • Android custom controls advanced 04-Canvas picture text
  • Android custom controls advanced 05-PATH basic operations
  • Android custom control advanced 06-Path bezier curve
  • The end of Android Custom controls Advanced 07-Path
  • Android custom controls advanced 08-PathMeasure details
  • Android custom control advanced 09- Control core Matrix principle
  • Android custom control advanced 10- control core Matrix Camera
  • Android custom controls Advanced 11- Event distribution mechanism principle
  • Android Custom controls Advanced 11- Event distribution mechanism 01
  • Android Custom controls Advanced 12- Event distribution mechanism principle 02
  • Android custom controls advanced 13-MotionEvent details
  • Android Custom Controls Advanced 14- Special controls event handling scheme