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

Android OnTouchListener长按增量异常:短按触发增量且抬起未停止

问题排查与修复方案

核心问题分析

  1. 短按后仍触发增量:ACTION_UP仅取消了CountDownTimer,但未取消postDelayed的延迟任务,导致手指抬起后,750ms延迟结束仍会启动计时器。
  2. CountDownTimer无法复用:CountDownTimer调用cancel()后无法再次调用start(),原代码复用同一个实例会导致后续长按无法触发增量。
  3. 触摸事件未消费:onTouch返回false,会让触摸事件继续向下传递,可能导致ACTION_UP事件未被当前监听器正确捕获。

修复后的代码

launchableSelectionView.setOnTouchListener(new View.OnTouchListener() {
    // 保存延迟任务引用,用于取消
    private Runnable longPressRunnable;
    // 保存计时器实例,用于取消
    private CountDownTimer countDownTimer;

    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        switch (motionEvent.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 每次按下创建新的延迟任务
                longPressRunnable = new Runnable() {
                    @Override
                    public void run() {
                        // 每次启动计时器都新建实例,避免复用已cancel的对象
                        countDownTimer = new CountDownTimer(Long.MAX_VALUE, 100) {
                            @Override
                            public void onTick(long l) {
                                MissileSystem system = bFittedToPlayer 
                                    ? game.GetOurPlayer().GetInterceptorSystem() 
                                    : game.GetSAMSite(lFittedToStructureID).GetInterceptorSystem();
                                int lFreeSlots = system.GetEmptySlotCount() - Types.size();
                                int lAvailableFunds = game.GetOurPlayer().GetWealth() - lTotalCost;

                                if (lFreeSlots == 0) {
                                    activity.ShowBasicOKDialog(context.getString(R.string.insufficient_slots));
                                    this.cancel(); // 无插槽时停止计时器
                                } else if (lAvailableFunds < game.GetConfig().GetInterceptorCost(type)) {
                                    activity.ShowBasicOKDialog(context.getString(R.string.insufficient_funds));
                                    this.cancel(); // 资金不足时停止计时器
                                } else {
                                    launchableSelectionView.IncrementNumber();
                                    AddType(type.GetID());
                                }
                            }

                            @Override
                            public void onFinish() {}
                        };
                        countDownTimer.start();
                    }
                };
                view.postDelayed(longPressRunnable, 750);
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                // 取消延迟任务和计时器
                if (longPressRunnable != null) {
                    view.removeCallbacks(longPressRunnable);
                }
                if (countDownTimer != null) {
                    countDownTimer.cancel();
                }
                break;
        }
        // 返回true,确保触摸事件被当前监听器消费,避免事件传递丢失
        return true;
    }
});

关键修复点

  • 取消延迟任务:在ACTION_UP和ACTION_CANCEL时调用removeCallbacks,取消未执行的延迟任务,避免短按后触发增量。
  • 新建CountDownTimer实例:每次长按触发时创建新的计时器,解决复用已cancel实例无法启动的问题。
  • 消费触摸事件:onTouch返回true,确保ACTION_UP等事件能被当前监听器正确捕获,防止事件传递导致的异常。
  • 边界情况处理:在无插槽或资金不足时主动取消计时器,避免无效循环。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 20:46:04