forward(q);
} else if (shouldDropInputEvent(q)) {
finish(q, false);
} else {
traceEvent(q, Trace.TRACE_TAG_VIEW);
final int result;
try {
result = onProcess(q);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
apply(q, result);
}
}
}
如上所示:
1.QueuedInputEvent是一种输入事件,链表结构,遍历传递给InputStage
2.InputStage是处理输入的责任链,在调用deliver时会遍历责任链传递事件
3.事件分发完成后会调用finishInputEvent,告知SystemServer进程的InputDispatcher线程,最终将该事件移除,完成此次事件的分发消费。
那么问题来了,InputStage的责任链是什么时候组件的呢?
[](()2.3 组装责任链
我们得回到ViewRootImpl.setView方法中
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
…
// Set up the input pipeline.
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;
…
}
}
可以看到在setView方法中,就把这条输入事件处理的责任链拼接完成了,不同的InputStage子类,通过构造方法一个个串联起来了,那这些InputStage到底干了啥呢?
-
SyntheticInputStage。综合处理事件阶段,比如处理导航面板、操作杆等事件。 -
ViewPostImeInputStage。视图输入处理阶段,比如按键、手指触摸等运动事件,我们熟知的view事件分发就发生在这个阶段。 -
NativePostImeInputStage。本地方法处理阶段,主要构建了可延迟的队列。 -
EarlyPostImeInputStage。输入法早期处理阶段。 -
ImeInputStage。输入法事件处理阶段,处理输入法字符。 -
ViewPreImeInputStage。视图预处理输入法事件阶段,调用视图view的dispatchKeyEventPreIme方法。 -
NativePreImeInputStage。本地方法预处理输入法事件阶段。
小结一下,事件到达应用端的主线程,会通过ViewRootImpl进行一系列InputStage来处理事件。这个阶段其实是对事件进行一些简单的分类处理,比如视图输入事件,输入法事件,导航面板事件等等。
我们的View触摸事件就发生在ViewPostImeInputStage阶段
final class ViewPostImeInputStage extends InputStage {
@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);
}
}
}
private int processPointerEvent(QueuedInputEvent q) {
final MotionEvent event = (MotionEvent)q.mEvent;
boolean handled = mView.dispatchPointerEvent(event)
return handled ? FINISH_HANDLED : FORWARD;
}
//View.java
public final boolean dispatchPointerEvent(MotionEvent event) {

本文深入探讨了Android事件分发机制,从组装责任链到事件在Activity、Window和View中的传递,详细解释了事件如何从WindowManager经由InputDispatcher到达View。文中还分析了在事件到达页面后,如何通过`onInterceptTouchEvent`和`dispatchTouchEvent`判断是否拦截事件,以及子View如何处理事件。最后讨论了滑动冲突的外部拦截法,并提供了模板代码。
最低0.47元/天 解锁文章
472

被折叠的 条评论
为什么被折叠?



