You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ACTION_DOWN触发后未收到ACTION_UP/ACTION_CANCEL事件的技术问询

Android系统手势取消后丢失ACTION_UP/ACTION_CANCEL事件的问题

结论先行

这个现象绝对不属于预期行为,完全违反了Android触摸事件的核心一致性规则——任何一个ACTION_DOWN都必须对应一个ACTION_UP或ACTION_CANCEL来闭合触摸序列。

复现验证

按照你给出的步骤,在Pixel 9 Pro这类使用系统手势的设备上确实能稳定复现:

  • 触发ACTION_DOWN后,从右侧滑出导航手势预览箭头
  • 向右滑动取消预览并松开手指
  • 日志只输出ACTION_DOWN(可能带少量ACTION_MOVE),完全没有结束事件
  • 直接导致触控游戏出现「人物一直处于按下状态」的恶性bug

问题根源

这是系统手势框架的边缘场景漏洞:当系统先劫持触摸事件用于手势预览,用户取消预览后,系统没有正确把触摸序列的收尾事件回传给应用的View层级,相当于触摸序列被「中途丢弃」了。

可行的临时规避方案

鉴于官方还没认可这个Issue,只能自己动手解决,分享几个实用方案:

  1. 触摸超时兜底:给每个ACTION_DOWN加个计时器,超过设定时长(比如500ms)没收到结束事件,就强制重置触摸状态
  2. 窗口焦点监听:在onWindowFocusChanged里,一旦窗口失去焦点,立刻重置所有触摸按下状态(比如切后台、弹出系统弹窗时)
  3. 边缘触摸过滤:游戏类应用可以直接忽略系统手势触发区的触摸事件,或者单独处理,避免触发手势预览

触摸超时方案示例代码

private Handler touchTimeoutHandler = new Handler(Looper.getMainLooper());
private Runnable resetTouchState = () -> {
    // 这里写你的触摸状态重置逻辑,比如停止角色移动、清除按下标记
    Log.d("TOUCH", "Force reset touch state (timeout fallback)");
};

@Override
public boolean onTouchEvent(MotionEvent event) {
    String actionStr = MotionEvent.actionToString(event.getAction());
    Log.d("TOUCH", actionStr);

    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            touchTimeoutHandler.postDelayed(resetTouchState, 500);
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            touchTimeoutHandler.removeCallbacks(resetTouchState);
            break;
    }
    return super.onTouchEvent(event);
}

后续建议

持续关注官方系统更新,一旦修复这个漏洞就可以移除临时方案;也可以尝试在开发者社区发起更多讨论,推动官方重视这个影响触控应用的问题。

内容的提问来源于stack exchange,提问作者l33t

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 22:32:43