Skip to content
阅读进度

冻屏或手势卡住,怎样排查输入链路? ​

返回 多屏互动项目 目录

标准回答 ​

我遇到过的显示问题包括冻屏或手势卡住。处理这类问题,我首先要分清楚:是手势没有进入业务处理,还是业务已经执行了、画面却没有更新。这两种现象看起来相似,定位方向完全不同。

具体看输入链路时,我会把手势触发时刻与回调进入、回调退出、业务状态变化对齐,并确认回调实际运行在哪个线程。它可能在主 Looper,也可能在 Binder 线程池或注册时指定的执行器上。只有知道线程和调用方式,才能判断一段耗时会阻塞 UI、拖住服务端调用,还是让专用队列积压。

如果事件已经到了,但回调很晚才返回,我会在 Trace 中继续区分 CPU 计算、锁等待、IO 和同步 Binder 等待。比如线程处于等待状态,就继续追它等的锁或远程线程;如果持续运行,就看是否有不必要的计算。只看到主线程忙,或者某条日志间隔很长,还不足以确定根因。

修复会对应阻塞点处理:把不影响当前手势决策的耗时工作迁出关键回调,让回调尽快返回;同时保证事件顺序、会话有效性和取消语义。高频移动事件能否合并要看业务,DOWN、UP、CANCEL 这类边界事件不能随意丢弃。简单地每次 new Thread,可能把卡顿变成乱序和资源失控。

验证时,我会在相同触发条件下复查回调耗时和排队情况,再覆盖连续手势、快速进入退出、取消和跨屏交接。如果输入与状态都正常推进而画面仍然冻结,就继续沿产帧、Surface 和展示链路定位,不会坚持把问题归到输入侧。

关键机制 ​

  • 记录手势开始、回调进入/退出、状态变化与画面展示时刻;只有一次日志打印,通常不足以判断丢事件。
  • 如果主线程忙,追计算、锁、同步 Binder 或 IO;如果远程回调线程被占,追调用是否同步、服务端是否串行等待与队列是否堆积。
  • 对非必要耗时工作,可在保证顺序、会话和取消语义的前提下迁出关键回调;高频事件按业务设计背压、合并或丢弃策略。

通俗例子 ​

假设回调中同步读文件花了 100ms,持续手势事件也走同一串行线程,后续事件就可能延迟。需要用实际 Trace 证明这条等待关系,再把读取迁出关键路径并验证顺序。

追问与回答 ​

IMS 回调一定在主线程吗? ​

不一定,先要说清 IMS 指哪个服务,输入管理和电话 IMS 不是一回事。即使是输入相关回调,线程也取决于接口实现、是否通过 Binder,以及注册时有没有传入 Handler 或 Executor。我会先看注册和回调转发代码,再通过线程名、线程 ID 和 Trace 确认。没有这些证据,不能根据服务简称就认定回调一定在主线程。

直接 new Thread 能解决吗? ​

它可能把耗时移走,但没有解决任务顺序和生命周期。连续手势可能创建大量线程,后发事件先完成,页面退出后旧任务还回写状态。我会优先用受控执行器,并按业务确定串行还是并行;结果回到 UI 时再次检查当前会话是否仍有效。必须同步给出的手势决策也不能随意异步化,否则可能改变原本的输入语义。

回调耗时就一定意味着事件丢失吗? ​

不一定。它首先说明处理变慢,后续可能排队、被合并、超时或影响另一条调用链,具体取决于接口和调度方式。要证明事件丢失,需要对齐输入端与消费端的事件序列或可关联标记,而不是看到日志少了就下结论。因此我会先使用“处理延迟”描述已观察到的现象,再根据证据判断有没有真正丢失。

易混淆点 ​

这里的 100ms 是示例。不能仅凭“回调里耗时”就认定系统缓冲区溢出或事件丢失;要核对具体服务、接口与调度方式。

参考资料 ​

内容来源 ​

用完整回答理解机制,用真实证据解释项目。