一句话总结
InputStage 是 Android 输入事件分发中的责任链处理器,输入事件从链头开始依次经过每个 Stage,每个 Stage 决定自己处理还是传给下一个。
1. 事件入口
ini
// ViewRootImpl.java
void deliverInputEvent(QueuedInputEvent q) {
InputStage stage;
if (q.event instanceof KeyEvent) {
stage = mFirstInputStage; // 按键事件:走按键链
} else {
stage = mFirstPostImeInputStage; // 触摸事件:走触摸链
}
stage.deliver(q);
}
代码分析
ViewRootImpl收到输入事件后,只负责选链头,不直接处理事件。- 按键事件和触摸事件走不同的责任链,因为两者的处理阶段不同。
stage.deliver(q)把事件交给链头,正式启动责任链传递。
2. InputStage 基本结构
java
// InputStage.java
abstract class InputStage {
private final InputStage mNext; // 链上的下一个 Stage
protected InputStage(InputStage next) {
mNext = next;
}
public final void deliver(QueuedInputEvent q) {
if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
finish(); // 事件已被消费,直接结束
} else {
onProcess(q); // 交给当前 Stage 处理
}
}
protected abstract int onProcess(QueuedInputEvent q);
protected void forward(QueuedInputEvent q) {
if (mNext != null) {
mNext.deliver(q); // 传给下一个 Stage
} else {
finish(); // 到达链尾,结束
}
}
}
代码分析
mNext是链表指针,把所有 Stage 串成一条链。deliver()是统一入口:先判断事件是否已被消费,没有则进入当前 Stage。onProcess()是抽象方法,由具体子类实现各自的处理逻辑。forward()负责把事件接力传下去,如果没有下一个就结束。
3. Stage 怎么处理事件
scss
// InputStage.java
protected void onProcess(QueuedInputEvent q) {
int result = onProcess(q);
if (result == FINISH_HANDLED) {
// 消费了事件,停止传递
finish();
} else if (result == FORWARD) {
// 不处理,交给下一个 Stage
forward(q);
}
}
代码分析
-
子类返回两个核心状态:
FINISH_HANDLED:我处理了,事件到此结束。FORWARD:我处理不了,继续往下传。
-
这是一种典型的责任链模式:每个节点尝试处理,不处理就转发。
4. 看一个具体子类
java
// ViewPostImeInputStage.java(简化版)
final class ViewPostImeInputStage extends InputStage {
public ViewPostImeInputStage(InputStage next) {
super(next);
}
@Override
protected int onProcess(QueuedInputEvent q) {
if (q.event instanceof MotionEvent) {
// 触摸事件交给 View 树分发
return processPointerEvent(q);
}
if (q.event instanceof KeyEvent) {
// 按键事件交给 DecorView 处理
return processKeyEvent(q);
}
return FORWARD; // 都不是,传给下一个 Stage
}
private int processPointerEvent(QueuedInputEvent q) {
MotionEvent event = (MotionEvent) q.event;
boolean handled = mView.dispatchPointerEvent(event);
return handled ? FINISH_HANDLED : FORWARD;
}
}
代码分析
ViewPostImeInputStage负责把事件交给视图树处理。onProcess()中根据事件类型分别处理,不能处理就返回FORWARD。processPointerEvent()把触摸事件派发给mView,由 View 树决定谁消费。- 如果 View 树消费了,返回
FINISH_HANDLED,链停止;否则继续传递。
5. 责任链是怎么串起来的
arduino
// ViewRootImpl.java(简化版)
mFirstInputStage = new NativePreImeInputStage(
new ViewPreImeInputStage(
new ImeInputStage(
new ViewPostImeInputStage(
new NativePostImeInputStage(
new SyntheticInputStage()
)
)
)
)
);
代码分析
- 通过构造函数的嵌套,把多个 Stage 串成一条链。
- 链头是
NativePreImeInputStage,链尾是SyntheticInputStage。 - 每个 Stage 的
mNext就是构造函数传入的下一个 Stage。 - 事件进入链头后,按顺序依次经过每个 Stage。
6. 完整执行流程
scss
事件进入 deliver()
│
▼
当前 Stage.deliver()
│
├── 已消费 → finish() → 结束
│
└── 未消费 → onProcess()
│
├── FINISH_HANDLED → finish() → 结束
│
└── FORWARD → forward() → mNext.deliver()
│
▼
到达链尾 → finish() → 结束
7. 总结
| 要点 | 说明 |
|---|---|
| 模式 | 责任链模式 |
| 入口 | ViewRootImpl.deliverInputEvent() |
| 传递 | InputStage.forward() 调用 mNext.deliver() |
| 消费 | 某个 Stage 返回 FINISH_HANDLED 即停止传递 |
| 链尾 | 无 mNext 时调用 finish() 结束 |
理解 InputStage 就是理解一条流水线:输入事件从链头流进,每个 Stage 看一眼,能处理就留下,不能处理就往下传,直到有人处理或流到末尾。