Preface
I read an article not long ago, which said " I don't recommend that you work too hard! ". After reading it, it feels very reasonable-the Android learning path, if you don't find the right direction and method of learning, it will be really thankless to learn.
Recently, I myself have been doing systematic data sorting. This is a relatively good article I found in the process of sorting. Now I share it with you, I hope it will be helpful to you.
Overview
Complete mastery of Android
the event distribution system is not easy, the entire process involved in the system boot process ( SystemServer
), input management ( InputManager
), system services, and communication of the UI ( ViewRootImpl
+ Window
+ WindowManagerService
), View
level event distribution mechanism and so on a series of links.
Event interception mechanism is based on the View
level of the event distribution mechanism to a point of advanced sexual knowledge, this article will explain more careful of them.
Event interceptor mechanism itself is relatively independent, so this does not require readers to the event distribution mechanism prior knowledge related to which the interested reader can refer to the following information:
Reflection | Design and Implementation of Android Event Distribution Mechanism
The overall structure of this article is as follows:
Speaking from the sequence of events
1. What is a sequence of events
Want to say clearing event distribution mechanism and event interception mechanism , the sequence of events is the first to understand the concept.
What is a sequence of events? Google
The official described the document as its The duration of the touch
name suggests, we can be understood as the user a full touch operation process - for example, the user clicks the button, the user slides the screen, users press the screen in a UI element and so on, All belong to this category.
2. Reason
Why sequence of events is a very important concept?
In the previous article , readers have already understood that the essential principle of event distribution is recursion. The simple way to implement this is: each time a new event is received, a recursion is required to find the corresponding consumption event View
, and return to the event distribution in turn. the result of.
With each touch event as the most basic unit, View
traverse the tree once recursively? The impact of this on performance is obvious, so this design has room for improvement.
How to improve this problem? The sequence of events as the most basic unit for processing is more appropriate.
First, the designer MotionEvent
adds an Action
attribute to describe the behavior of the event according to the user 's behavior:
ACTION_DOWN
: The act of touching the screen with a fingerACTION_MOVE
: The act of moving a finger on the screenACTION_UP
: The act of leaving the screen with a finger- …Other Actions, such as
ACTION_CANCEL
…
We know, for one-touch operation of the user, must correspond to a sequence of events , from the user's finger touches the screen to move your finger, and then lift your finger - must contain a single sequence of events ACTION_DOWN
, ACTION_MOVE
... ACTION_MOVE
, ACTION_UP
and many other events, which ACTION_MOVE
are The number is uncertain, ACTION_DOWN
and ACTION_UP
the number of sums is 1.
Familiar with the sequence of events concepts, designers can begin to design and improve existing code, that idea is as follows: when one received ACTION_DOWN
, the start means a complete sequence of events, through recursive traversal to find the real consumption of the event Child
, And save it . When the ACTION_MOVE
sum ACTION_UP
behavior is received later , the traversal recursion process is skipped and the event is directly distributed to the corresponding consumer:
Thus, the sequence of events in the event distribution of knowledge is indeed a very important core concepts (or no one), the most important is adequate saving performance : a normal touch user behavior, that sequence of events includes a number of A touch event, these events do not use recursive algorithms to find event consumers every time, because this consumes a lot of memory- when the sequence of events is more complex, or the View
tree is nested deeper, this advantage becomes more and more obvious.
So, how does the designer of the source code ensure that View
the child corresponding to the event consumer in the tree is found through a recursive algorithm View
, and what is its data structure?
If you think about it carefully, it is not difficult for readers to come to the answer: linked list .
Why is a linked list
Why use a linked list, and is there a simpler and more rude implementation solution?
Of course, the most intuitive way to achieve this seems to be: after the first event distribution is completed through recursion, the consumer of the event is saved as a member in the current parent View
:
Admittedly, such a design can achieve our desired effect, but the reader to think carefully about that, this is the biggest design problem destroyed the tree structure of internal autonomy .
Is it reasonable for the top level to View
directly hold a View
reference from the bottom level ? the answer is negative. First of all, this leads to View
confusion among hierarchical dependencies; second, the top layer View
itself holds a View
reference to one of the lowest layers , and View
the target
attributes of several levels in between are meaningless.
A more incisive way to apply the tree structure is to build a linked list:
Each View
node holds the next-level consumer of the event. When the subsequent touch event of the same event sequence arrives, it is no longer necessary to perform performance-consuming DFS
algorithms, but directly handed over to the next-level child View
, and the child View
is directly delivered to the next-level child . The next level of children View
until the event reaches the real consumer:
Similar to the definition of a linked list, the designer designs a TouchTarget
class and ViewGroup
declares such a member for each one as a node of the linked list to describe the transmission direction of the current sequence of events:
public abstract class ViewGroup extends View {
// 链表的下一级结点
private TouchTarget mFirstTouchTarget;
private static final class TouchTarget {
// 描述接下来的触摸事件由哪一个子View接收并分发
public View child;
}
}
So how is this linked list constructed? As mentioned above, when one ACTION_DOWN
is received , it means the beginning of a complete sequence of events. Recursive traversal is used to find the one that actually consumes the event.Child
Readers need to carefully try to figure out the sequence of events related concepts, because this knowledge throughout the entire distribution mechanism event flow, can be said to be the very core of knowledge; at the same time, it is also below grasp grasp the event interception mechanism critical.
Event interception mechanism
Most Android
developers of events to intercept mechanisms are not unfamiliar, the reader should have understood that the ViewGroup
level of additional design onInterceptTouchEvent()
functions and exposed to outside developers so as to achieve ViewGroup
not touch event to View
handle, but their own decision whether to consume Events, and feed back the results to the higher level ViewGroup
.
1. Reason
Why is such an interception mechanism designed? In fact, this is necessary. Taking the conventional ScrollView
corresponding sliding page as an example, when the user throws a list sliding operation, is the corresponding touch event sequence still necessary to be handed over to ScrollView
the child View
for processing?
The answer is no. When ScrollView
a sliding operation is received, of course, the events related to this sliding operation no longer need to be handed over to the child View
, but directly to ScrollView
handle the sliding operation.
Readers also need to understand that not all event sequences will be intercepted -when the user clicks ScrollView
on a certain button, the designer expects that the series of events corresponding to this click operation can be ScrollView
distributed to the child Button
for processing, so that the developer can eventually OnClickListener
Observe this click event in the button itself , and perform the corresponding business operation.
Therefore, for different types of ViewGroup
developers needs in different scenarios, decide whether to intercept the event, which the parent control according to their own responsibilities to intercept the sequence of events specified scene behavior, which we call the event interception mechanism .
2. Intercept function: onInterceptTouchEvent()
So developers how to do, to ensure that events of different scenarios are reasonably distributed directly down or intercept it? Accordingly designer provides onInterceptTouchEvent()
interception function:
public abstract class ViewGroup extends View {
public boolean onInterceptTouchEvent(MotionEvent ev) {
// ...
return false;
}
}
The definition is that when a touch event comes, the event is first passed into the onInterceptTouchEvent
function as a parameter , and the developer customizes the onInterceptTouchEvent
internal logic to decide whether to intercept the event and return the boolean
type of result. When the return value true
is, all subsequent events of the event sequence will be ViewGroup
intercepted by the current ; usually, ViewGroup
the function returns false
by default , that is, the event is not intercepted.
Text above example, we can ScrollView
add something like the following strategy - when a user initiates a click event when the operation onInterceptTouchEvent
returns false
, the event will give the child control downstream to decide whether or not the consumer; and when the user slides the screen , the event will Sequence for interception:
public class ScrollView extends ViewGroup {
public boolean onInterceptTouchEvent(MotionEvent ev) {
// 这里模拟一个抽象的函数代替实际的业务逻辑
// 实际源码中,这里是根据对触摸事件序列的复杂判断,得出操作是否是滑动事件
if (isUserScrollAction(ev)) {
return true;
} else {
return false;
}
}
}
The sequence of events in the process once again played a crucial role. For a single touch event - for example, ACTION_DOWN
or ACTION_MOVE
, we can not determine whether this is we want to intercept the operation. And when we get to the sequence of events after the number of consecutive events, we can according to the direction and distance of the gesture operation (to determine whether the slide), time of the touch screen (judge or long click event by event) to the user The behavior is defined and the final decision is made whether to intercept.
- This means that, when ScrollView
receiving the initial ACTION_DOWN
event, the parent control did not immediately intercept the incident, but to the child Button
to the consumer; and when receiving a number of ACTION_MOVE
events, ScrollView
the onInterceptTouchEvent()
function determination has been made of this The direction of the touch behavior is downward, which is a sliding event , and then the function returns true
, causing the current and subsequent touch events to be intercepted.
and many more! At this point, the reader seems to have inferred a weird conclusion: for the downward distribution process of a complete sequence of events, the consumer of the touch event does not necessarily have only one role -this does not seem to be intuitive.
But it is true.
Since a complete sequence of events that the event might give a different role, does this mean that in extreme cases, a user's sliding behavior will not only trigger the parent control itself sliding effect, users will also received Button
child control click effect?
This defect does exist in the design so far, so next we need to add new logic units to make up for this problem, and make a ACTION_CANCEL
shining debut.
3. ACTION_CANCEL: make up and end
Finally we came to the ACTION_CANCEL
stage, the announcer introduced this actor is two words: make up and end .
Now we hope that when Button
the parent control ScrollView
intercepts the sliding operation, Button
the click event will no longer be responded to.
In normal logic processing, it is Button
necessary to ACTION_UP
judge the duration of the entire event sequence when it is received . If it meets the pre-definition of a series of click operations (such as touchable = true
or clickable = true
etc.), it is directly handed over to the listener of the click event for View.OnClickListener
processing .
We can be ACTION_UP
regarded as a sequence of events in the termination event , it is clear that this logic in the event interception mechanism is not applicable because when the parent control of the event was to intercept, then the whole sequence all events are forwarded to the The parent control and child control can no longer receive any events, including ACTION_UP
.
We always want to stay the course (for example, look forward to the results of the interview timely feedback), event distribution mechanism is also the same, when the sub-control events are intercepted parent control, child controls also need a termination event notifications to make the corresponding behavior.
Therefore, the designer provides an additional ACTION_CANCEL
event to notify the current View
made to the event intercepted finishing after such cancellation or long-click event by event-related judgment logic timer (if any, the same below), or to The resetting of the calculation of the sliding distance of the current control, etc., avoids the embarrassing scene of "the parent control sliding occurs" and the "triggering child control click".
Now, when the parent control intercepts the touch event, the child control immediately receives an additional ACTION_CANCEL
compensation, and hastily carried out related finishing work, and then all the business logic is handed over to the parent control for processing.
Event interception mechanism seems to come to an end at this point. Readers think carefully, is this kind of logical processing perfect at present?
Interception mechanism and anti-interception mechanism
Parent control: "I invalidate your effect." Child control: "I invalidate your effect."
1. Oppression and resistance
The progress bar control of the music player SeekBar
made a serious protest.
As SeekBar
with ScrollView
the use of matching, the former shocked to discover that, as a child control, which is most proud of skills - slide to adjust the audio function is completely destroyed and progress.
Of course, ScrollView
when a sliding event is received, it will naturally intercept all subsequent related events, and the sub-controls ca SeekBar
n't even drink the soup.
This is an unreasonable design. The power of the parent control is too great, and the child control is completely helpless. So designers to ViewGroup
design another one API
- requestDisallowInterceptTouchEvent(boolean)
.
The role of this function is specified by the command ViewGroup
whether or not to intercept for the sequence of events , but a normal event to whether the child controls to deal with consumer events.
As SeekBar
an example, it can be designed like this:
public abstract class AbsSeekBar extends ProgressBar {
// ...代码大幅简化,具体逻辑请参考源码...
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
// 当接收到ACTION_DOWN事件时,命令父控件不能拦截事件序列
case MotionEvent.ACTION_DOWN:
mParent.requestDisallowInterceptTouchEvent(true);
break;
// ...
}
}
}
Now, even ScrollView
inside the hold of a slide operation related to the interception mechanism, but SeekBar
still can be a higher level of API
conduct of their repression, thus skips interception parent control and own consumption slip event - the end-user got his wish to get The operating experience (slide to adjust the playback progress).
2. Deeper thinking
The narrative in the previous section is inherently flawed. Generally speaking, the SeekBar
processing of adjusting the progress is horizontal sliding, and the ScrollView
processing is vertical sliding. In essence, the two logics do not conflict.
Describes, just to make it easier for readers to understand the anti interception mechanism corresponding to the requestDisallowInterceptTouchEvent()
purpose and significance of the design function, the reader does not have to go into this - of course, the reader may be a custom implementation of a lateral slide HorizontalScrollView
, in the previous section to obtain The effect of sliding conflicts will not be repeated in this article.
Another point to think about is, after the child control calls the requestDisallowInterceptTouchEvent(true)
function of the parent control to invalidate the interception mechanism of the parent control, does the invalidation of the interception mechanism of the parent control need to always exist ?
The answer is no, is the right way at some point in time should be the parent interception mechanism controls the restart - that call requestDisallowInterceptTouchEvent(false)
, so as to ensure that when touched to the other sub-control, parent control is still able to events interception mechanism for normal operation .
So how to grasp the time point of this reset ACTION_UP
, call it when the child control is received ?
In the child control termination event sequence of events in the reset state , this sounds good, but it needs to be noted that the interception mechanism is invalidated state is the presence of the parent control ViewGroup
of, and therefore a change in thinking, the better chance when not actually Is it hidden in ViewGroup
it?
3. Better timing
Designers will eventually reset the time on the parent control start event sequence of events - ACTION_DOWN
the processing logic.
public abstract class ViewGroup extends View {
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// ...
if (actionMasked == MotionEvent.ACTION_DOWN) {
// 1.这个函数内部将事件拦截功能的开关进行了重置
resetTouchState();
}
// ...2.继续处理事件拦截和事件分发
}
}
This is indeed a better time to reset the interception mechanism, which not only ensures that the touch events of other sub-controls will not be affected by the previous anti-interception mechanism, but also maintains the ViewGroup
autonomy of the internal itself.
This also proves that the sequence of events starting event ACTION_DOWN
can always be received parent control to intercept and process, therefore, can not in most cases the developers ViewGroup
of onInterceptTouchEvent()
the directly to the ACTION_DOWN
event returns true
, as this will cause the parent control to intercept the entire sequence of events , even the child controls ACTION_DOWN
are not acceptable, anti-interception mechanism completely ineffective.
to sum up
Event interception mechanism is a very important basic knowledge, but the sequence of events is one of the most central concepts, regardless of the event distribution or event interception , get to know the sequence of events meaning, understanding other logical concepts are no longer difficult.
Reference & additional words
Can this article help me understand the Android event interception mechanism?
Of course not. In the process of writing this article, the author finally deleted some more detailed knowledge points, such as:
- After the parent control intercepts the event,
mFirstTouchTarget
what happens to its internal changes? (Update operation of event delivery linked list) - What problems are often used to solve the problem of development in the event interception mechanism? (Resolve sliding conflict)
Etc. These details are just as important, they are filled event interception mechanism complete system of blood and flesh, the reader is advised herein in conjunction with the following relevant information to open a more detailed exploration trip.
- 1. Android source code
- 2. "Android Development Art Exploration"
Author: yet the Qing Mei sniffing
the original address: https: //juejin.cn/post/6844904128397705230
At last
I put the most important and popular learning direction materials for Android that I have compiled during this time on my GitHub: https://github.com/xieyuliang/Android Click here to see the blue font , and there are self-study in different directions. Programming route, interview question collection/face-to-face, and series of technical articles, etc.
The resources are continuously updated, and everyone is welcome to learn and discuss together.