从ViewRootImpl开始分析事件分发过程

前言

上篇“Android事件分发机制源码解析”分析了从Activity获取到触摸事件之后开始的分发流程,本篇就承接该篇介绍在触摸事件到达Activity之前的一些流程。

当点击屏幕产生一个触摸行为时,这个触摸行为则是通过底层硬件捕获传递到ViewRootImpl内的。由于底层相关的涉及到native相关的知识,这里就简单摘取传到Java层的主要部分,详细的过程感兴趣的同学可以查看这篇文章“Input系统—事件处理全过程”,而本篇就直接从ViewRootImpl接受到事件处开始展开。

时序图

分发流程的主题部分如下时序图所示:

时序图-触摸事件分发到Activity

下面将详细介绍其中的每个步骤。

Native

frameworks/base/core/jni/android_view_InputEventReceiver.cpp (点击查看完整源码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {

...

ScopedLocalRef<jobject> receiverObj(env, NULL);
bool skipCallbacks = false;
for (;;) {
uint32_t seq;
InputEvent* inputEvent;
// 读取InputEvent
status_t status = mInputConsumer.consume(&mInputEventFactory,
consumeBatches, frameTime, &seq, &inputEvent);

...

switch (inputEvent->getType()) {
case AINPUT_EVENT_TYPE_KEY:
//由Native的inputEvent来生成Java层的事件
inputEventObj = android_view_KeyEvent_fromNative(env,
static_cast<KeyEvent*>(inputEvent));
break;
...
}

if (inputEventObj) {
//执行Java层的InputEventReceiver.dispachInputEvent
env->CallVoidMethod(receiverObj.get(),
gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
...
}
}

...

}
}

可以看到最后是调用到了Java层的InputEventReceiver.dispachInputEvent()方法

InputEventReceiver

frameworks/base/core/java/android/view/InputEventReceiver.java(点击查看完整源码)

1
2
3
4
5
6
7
8
9
10
/**
* Provides a low-level mechanism for an application to receive input events.
* @hide
*/
public abstract class InputEventReceiver {
private void dispatchInputEvent(int seq, InputEvent event) {
mSeqMap.put(event.getSequenceNumber(), seq);
onInputEvent(event);
}
}

dispatchInputEvent()方法内部主要是调用了onInputEvent(event)方法。

而这里InputEventReceiver的实现类就是ViewRootImpl的内部类WindowInputEventReceiver

ViewRootImpl

从这里开始开始的流程就都是在Java层了。

WindowInputEventReceiver

frameworks/base/core/java/android/view/ViewRootImpl.java (点击查看完整源码)

1
2
3
4
5
6
7
8
final class WindowInputEventReceiver extends InputEventReceiver {

@Override
public void onInputEvent(InputEvent event) {
...
enqueueInputEvent(event, this, 0, true);
}
}

在子类WindowInputEventReceiver.onInputEvent()方法内调用了ViewRootImpl.enqueueInputEvent()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void enqueueInputEvent(InputEvent event,
InputEventReceiver receiver, int flags, boolean processImmediately) {
adjustInputEventForCompatibility(event);
//构建一个QueuedInputEvent
QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);

//将构建的QueuedInputEvent添加到pending队列末尾
QueuedInputEvent last = mPendingInputEventTail;
if (last == null) {
mPendingInputEventHead = q;
mPendingInputEventTail = q;
} else {
last.mNext = q;
mPendingInputEventTail = q;
}
//队列计数
mPendingInputEventCount += 1;
Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
mPendingInputEventCount);

//处理pending队列内的事件
if (processImmediately) {
doProcessInputEvents(); // 立即同步执行
} else {
scheduleProcessInputEvents();//通过handler分发执行
}
}

enqueueInputEvent()方法内将输入事件封装成QueuedInputEvent后加入队列末尾,之后再进行事件处理。

QueuedInputEvent回收池

其中QueuedInputEvent也是ViewRootImpl的内部类,成员变量mNext是用来链接下一个成员,从而组成一个单向链表。

其中mFlag是一个int型的标志位,在下方InputStage分发逻辑中有重要作用。可以看到WindowInputEventReceiver.onInputEvent()方法内调用enqueueInputEvent()方法时传入的flags行参值为0

1
2
3
4
5
6
7
8
9
 private static final class QueuedInputEvent {

public QueuedInputEvent mNext;

public InputEvent mEvent;
public InputEventReceiver mReceiver;
public int mFlags;
...
}

obtainQueuedInputEvent()recycleQueuedInputEvent()方法则是配合ViewRootImpl的成员变量mQueuedInputEventPoolSizemQueuedInputEventPool设计成了一个输入事件包装类QueuedInputEvent的回收池,便于QueuedInputEvent的重复使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
* 1. 判断mQueuedInputEventPool回收池内是否有缓存的对象,若有则取出一个
* 2. 若第一步内没有取到,则直接新建一个QueuedInputEvent对象
* 3. 将入参保存到QueuedInputEvent对象内
*/
private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
InputEventReceiver receiver, int flags) {
QueuedInputEvent q = mQueuedInputEventPool;
if (q != null) {
mQueuedInputEventPoolSize -= 1;//QueuedInputEvent回收池由于取出一个后数量减1
mQueuedInputEventPool = q.mNext;
q.mNext = null;
} else {
q = new QueuedInputEvent();
}

q.mEvent = event;
q.mReceiver = receiver;
q.mFlags = flags;
return q;
}

/**
* 若当前回收池内的数量没有超过MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10,则将其放入回收池内
*/
private void recycleQueuedInputEvent(QueuedInputEvent q) {
q.mEvent = null;
q.mReceiver = null;

if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) {
mQueuedInputEventPoolSize += 1;//QueuedInputEvent回收池由于放入一个后数量加1
q.mNext = mQueuedInputEventPool;
mQueuedInputEventPool = q;
}
}

// Pool of queued input events.
private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10;

doProcessInputEvents

再回到enqueueInputEvent()方法内,分析最后几行

1
2
3
4
5
6
//处理pending队列内的事件
if (processImmediately) {
doProcessInputEvents(); // 立即同步执行
} else {
scheduleProcessInputEvents();//通过handler分发执行
}

processImmediately表示是否立即同步执行,在WindowInputEventReceiver回调内传入的是true,执行doProcessInputEvents()。而当false异步时,则调用到scheduleProcessInputEvents()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private void scheduleProcessInputEvents() {
if (!mProcessInputEventsScheduled) {
mProcessInputEventsScheduled = true;
Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
}
}

final ViewRootHandler mHandler = new ViewRootHandler();

final class ViewRootHandler extends Handler {

...

@Override
public void handleMessage(Message msg) {
switch (msg.what) {
...
case MSG_PROCESS_INPUT_EVENTS:
mProcessInputEventsScheduled = false;
doProcessInputEvents();
break;
...
}
}

可以看到最后还是调用到了doProcessInputEvents()方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void doProcessInputEvents() {
// Deliver all pending input events in the queue.
while (mPendingInputEventHead != null) {
QueuedInputEvent q = mPendingInputEventHead;
mPendingInputEventHead = q.mNext;
if (mPendingInputEventHead == null) {
mPendingInputEventTail = null;
}
q.mNext = null;

mPendingInputEventCount -= 1;
...

deliverInputEvent(q);
}

// 处理完所有输入事件后,清除标志位
if (mProcessInputEventsScheduled) {
mProcessInputEventsScheduled = false;
mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
}
}

doProcessInputEvents()方法内就是通过一个while循环遍历链表中的输入事件,调用deliverInputEvent()进行事件分发处理。

这里的mPendingInputEventHead链表就是上面的enqueueInputEvent()方法将内输入事件包装类插入的链表。

最后处理完所有输入事件后,清除标志位。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private void deliverInputEvent(QueuedInputEvent q) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
q.mEvent.getSequenceNumber());
...

InputStage stage;
if (q.shouldSendToSynthesizer()) {
stage = mSyntheticInputStage;
} else {
stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
}

if (stage != null) {
handleWindowFocusChanged();
stage.deliver(q);
} else {
finishInputEvent(q); //结束事件分发
}
}

deliverInputEvent

deliverInputEvent()方法从方法名就可以知道它的作用是分发事件。

方法内最主要的就是InputStage,最终要么是调用了stage.deliver(q),要么就是stage为空直接结束事件分发。

而stage赋值处的几个InputStage子类是在ViewRootImpl.setView()方法内实例化的,这个方法在窗口管理和view绘制方面起到非常重要的作用,这部分之后会抽空再单独详细讲解。所以在View绘制之后所触发的事件,这里的7个InputStage子类都是不为空的。

而从这7个InputStage子类的构造器来看,就是典型的责任链模式,即自己能处理就自己处理,若不能处理则交给下一个处理,从下面InputStage的源码也能证实责任链模式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
int userId) {
...
mSyntheticInputStage = new SyntheticInputStage();
InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
"aq:native-post-ime:" + counterSuffix);
InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
InputStage imeStage = new ImeInputStage(earlyPostImeStage,
"aq:ime:" + counterSuffix);
InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
"aq:native-pre-ime:" + counterSuffix);

mFirstInputStage = nativePreImeStage;
mFirstPostImeInputStage = earlyPostImeStage;
...
}
  • NativePreImeInputStage: 主要是为了将消息放到NativeActivity中去处理, NativeActivity和普通Acitivty的功能区别不大,只是很多代码都在native层去实现,这样执行效率更高,并且NativeActivity在游戏开发中很实用。
  • ViewPreImeInputStage: 从名字中就可得知,最后会调用Acitivity的所有view的onkeyPreIme方法,这样就给View在输入法处理key事件之前先得到消息并处理的机会。
  • ImeInputStage: ImeInputStage的onProcess方法会调用InputMethodManager的dispatchInputEvent方法处理消息。
  • EarlyPostImeInputStage: 屏幕上有焦点的View会高亮显示,用来提示用户焦点所在。
  • NativePostImeInputStage: 为了让IME处理完消息后能先于普通的Activity处理消息。
  • ViewPostImeInputStage: Acitivity和view处理各种消息。
  • SyntheticInputStage: 流水线的最后一级,经过层层过滤之后,到达这里的消息已经不多了,例如手机上的虚拟按键消息。

那么Activity和View的事件处理主要对应的InputStage是ViewPostImeInputStage。

类图:

InputStage类图

InputStage详解

源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/**
* Base class for implementing a stage in the chain of responsibility
* for processing input events.
* <p>
* Events are delivered to the stage by the {@link #deliver} method. The stage
* then has the choice of finishing the event or forwarding it to the next stage.
* </p>
*/
abstract class InputStage {
private final InputStage mNext;//持有的下一个stage对象

//3种状态
protected static final int FORWARD = 0;//当前stage不处理,会将事件传递给下个stage处理
protected static final int FINISH_HANDLED = 1;//当前stage已处理,会调用finish,stage链上剩余的都不会处理该事件
protected static final int FINISH_NOT_HANDLED = 2;//当前stage未处理,会调用finish,stage链上剩余的都不会处理该事件

private String mTracePrefix;

/**
* Creates an input stage.
* @param next The next stage to which events should be forwarded.
*/
public InputStage(InputStage next) {
mNext = next;
}

/**
* Delivers an event to be processed.
* 分发事件
*/
public final void deliver(QueuedInputEvent q) {
if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
forward(q);//当前stage不处理,直接传给下一个(即:mNext)
} else if (shouldDropInputEvent(q)) {//判断事件是否需要丢弃
finish(q, false);//结束调用,stage链上的各个stage都不会处理这个事件
} else {
traceEvent(q, Trace.TRACE_TAG_VIEW);
final int result;
try {
result = onProcess(q);//在onProcess()内处理具体的操作
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
apply(q, result);//根据onProcess()返回的状态值result判断是传递给下个stage处理还是结束
}
}

/**
* Marks the the input event as finished then forwards it to the next stage.
* finish方法主要是给QueuedInputEvent的mFlags标志位设置FLAG_FINISHED状态,且当handled = true时,设
* 置FLAG_FINISHED_HANDLED标志,以表示事件已被处理。
* 当事件在stage内传递完毕后会调用finishInputEvent(),该方法内就会取出FLAG_FINISHED_HANDLED标志状态回调给mReciver
*/
protected void finish(QueuedInputEvent q, boolean handled) {
q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
if (handled) {
q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
}
forward(q);
}

/**
* Forwards the event to the next stage.
* 将事件分发给下个stage
*/
protected void forward(QueuedInputEvent q) {
onDeliverToNext(q);
}

/**
* Applies a result code from {@link #onProcess} to the specified event.
* 根据onProcess()返回的状态值result判断是传递给下个stage处理还是结束
*/
protected void apply(QueuedInputEvent q, int result) {
if (result == FORWARD) {
forward(q);
} else if (result == FINISH_HANDLED) {
finish(q, true);
} else if (result == FINISH_NOT_HANDLED) {
finish(q, false);
} else {
throw new IllegalArgumentException("Invalid result: " + result);
}
}

/**
* Called when an event is ready to be processed.
* @return A result code indicating how the event was handled.
* 具体处理逻辑处,默认是无实现,直接返回FORWARD值,交给下个stage处理
*/
protected int onProcess(QueuedInputEvent q) {
return FORWARD;
}

/**
* Called when an event is being delivered to the next stage.
* 若stage未分发完毕,则继续分发处理;
* 否则调用finishInputEvent方法结束stage的链式调用
*/
protected void onDeliverToNext(QueuedInputEvent q) {
if (DEBUG_INPUT_STAGES) {
Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q);
}
if (mNext != null) {
mNext.deliver(q);
} else {
finishInputEvent(q);
}
}

protected void onWindowFocusChanged(boolean hasWindowFocus) {
if (mNext != null) {
mNext.onWindowFocusChanged(hasWindowFocus);
}
}

protected void onDetachedFromWindow() {
if (mNext != null) {
mNext.onDetachedFromWindow();
}
}

protected boolean shouldDropInputEvent(QueuedInputEvent q) {
if (mView == null || !mAdded) {
Slog.w(mTag, "Dropping event due to root view being removed: " + q.mEvent);
return true;
} else if ((!mAttachInfo.mHasWindowFocus
&& !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)
&& !isAutofillUiShowing()) || mStopped
|| (mIsAmbientMode && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_BUTTON))
|| (mPausedForTransition && !isBack(q.mEvent))) {
// This is a focus event and the window doesn't currently have input focus or
// has stopped. This could be an event that came back from the previous stage
// but the window has lost focus or stopped in the meantime.
if (isTerminalInputEvent(q.mEvent)) {
// Don't drop terminal input events, however mark them as canceled.
q.mEvent.cancel();
Slog.w(mTag, "Cancelling event due to no window focus: " + q.mEvent);
return false;
}

// Drop non-terminal input events.
Slog.w(mTag, "Dropping event due to no window focus: " + q.mEvent);
return true;
}
return false;
}

void dump(String prefix, PrintWriter writer) {
if (mNext != null) {
mNext.dump(prefix, writer);
}
}

private boolean isBack(InputEvent event) {
if (event instanceof KeyEvent) {
return ((KeyEvent) event).getKeyCode() == KeyEvent.KEYCODE_BACK;
} else {
return false;
}
}

private void traceEvent(QueuedInputEvent q, long traceTag) {
if (!Trace.isTagEnabled(traceTag)) {
return;
}

if (mTracePrefix == null) {
mTracePrefix = getClass().getSimpleName();
}
Trace.traceBegin(traceTag, mTracePrefix + " id=0x"
+ Integer.toHexString(q.mEvent.getId()));
}
}

流程图

InputStage流程图

说明

InputStage主要方法有这几个:

  • void deliver(QueuedInputEvent q):这是deliverInputEvent()方法内的satge直接调用的入口。

  • void forward(QueuedInputEvent q)onDeliverToNext(QueuedInputEvent q):forword内直接调用了onDeliverToNext。后者方法内判断当前stage是否为stage链上的最后一项(即:mNext == null)。若是,则调用finishInputEvent(q)将处理结果返回给mReceiver,否则就继续传递给下一个stage判断处理(mNext.deliver(q))

  • boolean shouldDropInputEvent(QueuedInputEvent q): 判断事件是否需要丢弃

  • int onProcess(QueuedInputEvent q) :具体处理逻辑处,默认是无实现,直接返回FORWARD值,交给下个stage处理

  • void apply(QueuedInputEvent q, int result) :根据onProcess()返回的状态值result判断是传递给下个stage处理还是结束,这里的结束并不是直接跳出stage链内的调用,而是在链内逐个stage遍历时每个stage都不处理,直到责任链尾时(mNext == null)调用finishInputEvent方法返回本次执行结果。

  • void finish(QueuedInputEvent q, boolean handled) :给QueuedInputEvent的mFlags标志位设置FLAG_FINISHED状态,且当handled = true时,设置FLAG_FINISHED_HANDLED标志,以表示事件已被处理。当事件在stage内传递完毕后会调用finishInputEvent(),该方法内就会取出FLAG_FINISHED_HANDLED标志状态并回调给mReceiver

onProcess()返回的三种类型:

  • FORWARD = 0 :当前stage不处理,会将事件传递给下个stage处理
  • FINISH_HANDLED = 1 : 当前stage已处理,会调用finish,stage链上剩余的都不会处理该事件
  • FINISH_NOT_HANDLED = 2 : 当前stage未处理,会调用finish,stage链上剩余的都不会处理该事件

其中FINISH_HANDLED 和FINISH_NOT_HANDLED在stage责任链模式上传递时的表现行为是完全一致的,即之后的stage都不会处理。只是在finishInputEvent内会将该值取出(表示该事件是否已被消费)回调给mReceiver

1
2
3
4
5
6
7
8
9
10
11
12
13
private void finishInputEvent(QueuedInputEvent q) {

if (q.mReceiver != null) {
boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
...
q.mReceiver.finishInputEvent(q.mEvent, handled);

} else {
q.mEvent.recycleIfNeededAfterDispatch();
}

recycleQueuedInputEvent(q);
}

finishInputEvent方法就是将执行结果handled返回给mReceiver,最后调用recycleQueuedInputEvent(q)将QueuedInputEvent对象回收。

ViewPostImeInputStage#onProcess()

InputStage内的具体执行流程分析完了,接下来就可以去看看ViewPostImeInputStage.onProcess()具体执行了什么。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
final class ViewPostImeInputStage extends InputStage {
public ViewPostImeInputStage(InputStage next) {
super(next);
}

@Override
protected int onProcess(QueuedInputEvent q) {
if (q.mEvent instanceof KeyEvent) {
return processKeyEvent(q);//处理键盘事件
} else {
final int source = q.mEvent.getSource();
if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
return processPointerEvent(q);//处理触摸事件
} else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
return processTrackballEvent(q);//处理轨迹球事件
} else {
return processGenericMotionEvent(q);
}
}
}
}

ViewPostImeInputStage.onProcess()内有判断当前事件类型,我们这边分析触摸事件,所以直接看processPointerEvent(q)。对其他事件感兴趣的可以自行查看源码分析。

1
2
3
4
5
6
7
private int processPointerEvent(QueuedInputEvent q) {
final MotionEvent event = (MotionEvent)q.mEvent;
...
boolean handled = mView.dispatchPointerEvent(event);
...
return handled ? FINISH_HANDLED : FORWARD;
}

这里就可以看到ViewPostImeInputStage.onProgress()返回的具体值handled ? FINISH_HANDLED : FORWARD

FINISH_HANDLED:当前触摸事件由ViewPostImeInputStage处理;FORWARD:ViewPostImeInputStage未处理,继续传给SyntheticInputStage处理。

当然,processPointerEvent内的主角是mView.dispatchPointerEvent(event)。mView是ViewRootImpl的成员变量,该变量是在ViewRootImpl.setView()内赋值的。ViewRootImpl.setView()方法在上面介绍deliverInputEvent()方法内的InputStage初始化实例时就提到过。

ViewRootImpl#setView行参view具体类型确定

frameworks/base/core/java/android/view/ViewRootImpl.java (点击查看源码)

1
2
3
4
5
6
7
8
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
int userId) {
synchronized (this) {
if (mView == null) {
mView = view;
...
}
}

这里view的入参类型是View,所以还得看看ViewRootImpl.setView()方法具体是哪里调用的,且view的具体类型是什么。

这里就直接给出结论:DecorView

调用过程:ActivityThread.handleResumeActivity() -> WindowManagerImpl.addView() -> WindowManagerGlobal.addView() -> ViewRootImpl.setView()

这里的涉及到的具体细节将在下篇介绍Window相关知识的时候再详细展开说明。

frameworks/base/core/java/android/app/ActivityThread.java(点击查看源码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {
...
final Activity a = r.activity;
...

r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
...
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
wm.addView(decor, l);//这里的wm的具体实现类是WindowManagerImpl
}
}
...
}

frameworks/base/core/java/android/view/WindowManagerImpl.java(点击查看源码)

1
2
3
4
5
6
7
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();

public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
mContext.getUserId());
}

frameworks/base/core/java/android/view/WindowManagerGlobal.java(点击查看源码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow, int userId) {
...
root = new ViewRootImpl(view.getContext(), display);

view.setLayoutParams(wparams);

mViews.add(view);
mRoots.add(root);
mParams.add(wparams);

// do this last because it fires off messages to start doing things
try {
root.setView(view, wparams, panelParentView, userId);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}

View#dispatchPointerEvent、DecorView#dispatchTouchEvent()

在确认了view的类型是DecorView后,在DecorView源码内搜索时确没有找到dispatchPointerEvent方法,那就从父类中查找(DecorView -> FrameLayout -> ViewGroup -> View),直到在View内才找到该方法。

frameworks/base/core/java/android/view/View.java(点击查看源码)

1
2
3
4
5
6
7
public final boolean dispatchPointerEvent(MotionEvent event) {
if (event.isTouchEvent()) {
return dispatchTouchEvent(event);
} else {
return dispatchGenericMotionEvent(event);
}
}

可以看到,这里会判断当前是否为触摸事件,如果是则调用dispatchTouchEvent(event)

frameworks/base/core/java/com/android/internal/policy/DecorView.java(点击查看源码)

1
2
3
4
5
public boolean dispatchTouchEvent(MotionEvent ev) {
final Window.Callback cb = mWindow.getCallback();
return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
}

回到DecorView.dispatchTouchEvent(),这里会调用cb.dispatchTouchEvent(ev),cb为Window.Callback类型。

frameworks/base/core/java/android/view/Window.java(点击查看源码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public interface Callback {
/**
* Called to process key events. At the very least your
* implementation must call
* {@link android.view.Window#superDispatchKeyEvent} to do the
* standard key processing.
*
* @param event The key event.
*
* @return boolean Return true if this event was consumed.
*/
public boolean dispatchKeyEvent(KeyEvent event);


/**
* Called to process touch screen events. At the very least your
* implementation must call
* {@link android.view.Window#superDispatchTouchEvent} to do the
* standard touch screen processing.
*
* @param event The touch screen event.
*
* @return boolean Return true if this event was consumed.
*/
public boolean dispatchTouchEvent(MotionEvent event);
...
}

而Activity类实现了这个回调,并且在Activity.attach()方法内给PhoneWindow设置CallBack回调。

frameworks/base/core/java/android/app/Activity.java(点击查看源码)

1
2
3
4
5
6
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback,
AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
attachBaseContext(context);

mFragments.attachHost(null /*parent*/);

mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(mWindowControllerCallback);
mWindow.setCallback(this);//设置回调
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
...
}
1
2
3
4
5
6
7
8
9
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}

分析到这里就回到平时从Activity开始分析的事件分发流程的起点了。从Activity.dispatchTouchEvent()开始分析事件分发的过程就可以看小编之前的文章“Android事件分发机制源码解析”了。

参考

Android Input(六)-ViewRootImpl接收事件

Input系统—事件处理全过程

Android Code Search

坚持原创技术分享,您的支持是对我最大的鼓励!