外观
IMS 怎样把一次触摸送到按钮?WMS 在哪里参与?
标准回答
IMS 这里指 InputManagerService,它协调 Android 的输入设备与输入系统。触摸信号先由驱动上报,EventHub 读取底层事件,InputReader 结合设备配置转换成 Android 输入事件,再交给 InputDispatcher 决定如何分发。
InputDispatcher 根据显示区域、可触摸窗口、坐标、焦点和系统策略等信息选择目标。触摸通常看坐标命中和当前手势归属,按键通常与焦点有关,不能简单说所有事件都发给最上面或当前焦点窗口。窗口信息由窗口与显示相关系统链路协调提供,WMS 是其中的重要参与者。
事件通过输入通道到应用侧,由 ViewRootImpl 等接收,再进入 Activity、DecorView 和 View 树的分发链路。ViewGroup 决定是否拦截,子 View 的监听器与 onTouchEvent 继续处理;符合点击条件时才触发 onClick。系统的 InputDispatcher 不会直接查找一个按钮并调用它的 onClick。
因此,点了没反应要分层查:底层有没有事件,系统选中了哪个显示和窗口,应用是否及时接收,View 是否拦截或消费,以及主线程是否阻塞。应用长时间不能完成输入处理,可能触发输入相关 ANR;没有正确的可聚焦窗口等情况也可能造成输入问题,不能只盯业务点击回调。
关键机制
- 设备侧:驱动 → EventHub → InputReader,得到 Android 输入事件。
- 系统侧:InputDispatcher 根据窗口信息和策略确定目标,通过输入通道交接。
- 应用侧:ViewRootImpl 接收,Activity / View 树分发,控件决定如何消费。
通俗例子
屏幕上按钮可见,但上方有透明且可触摸的窗口覆盖:触摸可能被上层窗口接收,按钮的 onTouchEvent 根本没有机会执行。此时需要查窗口及输入目标,而不只是修改按钮点击监听。
追问与回答
注册的输入回调里做耗时工作,会造成什么?
要先确认是哪一种回调、由哪个线程分发。普通触摸回调在主线程做耗时操作,会拖住输入处理和绘制;某些系统监控或原生输入回调还要求及时确认处理完成,拖延可能造成排队或超时。不能仅凭“注册了 IMS 回调”断言必然丢事件,应检查回调契约、线程、确认时机和队列证据。
onTouch 返回 true 和 onClick 有什么关系?
对通常处于 enabled 状态的 View,如果 OnTouchListener 消费了事件,后续 onTouchEvent 通常不会处理该事件,默认点击识别也就可能无法完成。onClick 不是每次触摸必定出现的独立通知,而是满足点击条件后的结果。自定义消费触摸并需要点击语义时,应在合适条件调用 performClick,兼顾可访问性。
易混淆点
InputManagerService 与 InputMethodManagerService 不同,后者与软键盘等输入法管理有关;IMS 也不是 View 的事件拦截方法。输入事件传输不是每个触点都通过普通 Binder 方法调用 onTouchEvent。
参考资料
内容来源
- Android 技术札记 · 原条目
ims-input