一句话总结:
MotionEvent 的传递像快递配送,从工厂(硬件)发货,经物流中心(系统服务),跨城运输(Binder 跨进程),最终送货上门(App),每个环节必须卡准时间,否则快递丢件(卡顿)!
一、硬件层:触摸事件诞生
1. 触摸屏检测(工厂生产)
- 电容变化:手指触碰屏幕 → 改变局部电容值。
- 驱动处理:触控芯片将电容变化转为电信号,生成原始数据(坐标、压力、时间戳)。
2. Linux 内核层(物流分拣)
-
Input 子系统:
evdev
驱动:将原始数据封装成标准输入事件(struct input_event
)。- 设备节点:写入
/dev/input/eventX
(X 代表不同输入设备)。
二、系统服务层:事件加工与分发
1. InputReader(物流中心分拣员)
-
监听设备节点:通过
EventHub
读取/dev/input/eventX
的原始事件。 -
加工事件:
- 合并多点触控:处理多指操作的
pointerId
。 - 添加动作类型:标记为
ACTION_DOWN
、MOVE
、UP
、CANCEL
。 - 坐标转换:根据屏幕旋转调整坐标。
- 合并多点触控:处理多指操作的
2. InputDispatcher(快递派送员)
-
确定目标窗口:
- 根据坐标和窗口层级(Z-Order)找到最顶层的
Window
(如当前 Activity 的窗口)。
- 根据坐标和窗口层级(Z-Order)找到最顶层的
-
跨进程传递:
- Binder 通信:将事件通过
IWindow
接口发送到目标应用的主线程消息队列。 - 同步屏障:确保事件按顺序处理(
DOWN
→MOVE
→UP
)。
- Binder 通信:将事件通过
// 伪代码: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 节拍,流畅不卡顿!