InputStage 责任链核心执行流程

一句话总结

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 看一眼,能处理就留下,不能处理就往下传,直到有人处理或流到末尾。

相关推荐
北京自在科技2 小时前
谷歌安卓 Gemini 迎来界面改版,Find Hub 接入 Gemini 支持物品记忆查找
android·安卓
YB13754 小时前
Jetpack Compose 动画Modifier.animateItem()
android
2401_885885045 小时前
巴林语音通知接口如何对接?系统告警语音API接入教程
android·前端·网络·python·语音识别
收纳过往5 小时前
数据库加索引的时机:慢查询日志说话
android·开发语言·数据库·python·低代码·rxjava
狂热开发者6 小时前
车载中控要给鸿蒙用户,能不能和 Android 共用一个二维码?
android·华为·harmonyos
.Bryce.7 小时前
T2-LLM评测不等于Agent评测
android·java·人工智能·后端·gpt·agent·1024程序员节
美狐美颜SDK开放平台8 小时前
视频美颜SDK如何应对快速转头与大幅度面部动作?
android·人工智能·ios·音视频·直播美颜sdk·视频美颜sdk
2601_968900778 小时前
玻璃深加工的工艺窗口:4 道工序的温度与时间参数边界
android·java·javascript
好的佩奇018 小时前
Dart 之类修饰符
android·flutter·dart
YB13758 小时前
Jetpack Compose 动画Modifier.animateContentSize()
android