一句话说透Android里面的MotionEvent传递顺序,深入系统底层

212 阅读3分钟

一句话总结
MotionEvent 的传递像快递配送,从工厂(硬件)发货,经物流中心(系统服务),跨城运输(Binder 跨进程),最终送货上门(App),每个环节必须卡准时间,否则快递丢件(卡顿)!


一、硬件层:触摸事件诞生

1. 触摸屏检测(工厂生产)

  • 电容变化:手指触碰屏幕 → 改变局部电容值。
  • 驱动处理:触控芯片将电容变化转为电信号,生成原始数据(坐标、压力、时间戳)。

2. Linux 内核层(物流分拣)

  • Input 子系统

    • evdev 驱动:将原始数据封装成标准输入事件(struct input_event)。
    • 设备节点:写入 /dev/input/eventX(X 代表不同输入设备)。

二、系统服务层:事件加工与分发

1. InputReader(物流中心分拣员)

  • 监听设备节点:通过 EventHub 读取 /dev/input/eventX 的原始事件。

  • 加工事件

    • 合并多点触控:处理多指操作的 pointerId
    • 添加动作类型:标记为 ACTION_DOWNMOVEUPCANCEL
    • 坐标转换:根据屏幕旋转调整坐标。

2. InputDispatcher(快递派送员)

  • 确定目标窗口

    • 根据坐标和窗口层级(Z-Order)找到最顶层的 Window(如当前 Activity 的窗口)。
  • 跨进程传递

    • Binder 通信:将事件通过 IWindow 接口发送到目标应用的主线程消息队列。
    • 同步屏障:确保事件按顺序处理(DOWN → MOVE → UP)。
// 伪代码:InputDispatcher 分发逻辑
void InputDispatcher::dispatchEventLocked() {
    // 找到目标窗口
    sp<InputWindowHandle> window = findTouchedWindow();
    // 发送事件到应用进程
    window->sendEvent(event);
}

三、应用层:事件处理

1. 主线程接收(快递到站)

  • 消息队列:通过 Looper 接收到 MotionEvent,触发 ViewRootImpl 的 dispatchInputEvent()

2. ViewRootImpl(小区快递柜)

  • 坐标转换:将全局坐标转换为当前窗口的局部坐标。
  • 分发入口:调用 DecorView 的 dispatchPointerEvent()

3. View 树层级分发(上门送货)

  • Activity → Window → DecorView → ViewGroup → View

    • 拦截机制:父容器可通过 onInterceptTouchEvent() 截胡。
    • 消费机制:子 View 通过 onTouchEvent() 决定是否签收。
// 伪代码:View 树分发逻辑
public boolean dispatchTouchEvent(MotionEvent event) {
    if (onInterceptTouchEvent(event)) { // 父容器截胡
        return onTouchEvent(event); 
    }
    return child.dispatchTouchEvent(event); // 继续下发
}

四、底层关键机制

1. Vsyn 同步(物流节拍器)

  • 节奏控制:屏幕刷新率(如 60Hz)决定事件处理必须在 16ms 内完成。
  • Choreographer:协调 UI 绘制与事件处理,避免撕裂或卡顿。

2. SurfaceFlinger(快递最终配送)

  • 合成显示:将处理后的界面数据提交到屏幕驱动。
  • 双缓冲机制:避免绘制过程中的闪烁(Back Buffer 和 Front Buffer 交换)。

五、事件传递的“堵车”风险点

环节风险解决方案
InputDispatcher 延迟系统服务过载,事件堆积优化系统服务,减少后台进程
主线程阻塞应用处理事件耗时过长(如主线程 IO)异步处理,精简 onTouch 逻辑
View 树层级过深测量布局耗时超标扁平化布局,使用 ConstraintLayout

六、总结:事件的一生

手指触摸 → 触控驱动 → /dev/input/eventX → InputReader → InputDispatcher  
               ↓  
Binder 跨进程 → App 主线程 → ViewRootImpl → Activity → View 树  
               ↓  
Vsync 同步 → SurfaceFlinger → 屏幕显示

口诀

  • 硬件产事件,内核转结构
  • Reader 加工,Dispatcher 派送
  • 跨进程进 App,View 树层层送
  • 卡准 Vsync 节拍,流畅不卡顿!