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

Android中VIBRATOR_SERVICE的cancel()无法取消振动问题求助

Android VIBRATOR_SERVICE 取消并重启振动的问题解决

环境信息

  • 编译SDK版本:33
  • 测试设备:Pixel 6

问题场景

需要实现「振动运行过程中取消当前振动,立即启动新的振动指令(可自定义强度/时长)」的逻辑,但实际测试发现:调用cancel()后启动新振动,后续的取消操作完全失效,新振动会持续到预设时长结束。

示例代码

正常工作的代码(振动1秒后停止)

// 创建Vibrator实例
Vibrator vib = (Vibrator) MainActivity.this.getSystemService(Context.VIBRATOR_SERVICE);

AudioAttributes audioAttributes = new AudioAttributes.Builder()
    .setUsage(AudioAttributes.USAGE_GAME)
    .build();

// 启动20秒振动(会被后续取消)
vib.vibrate(20000, audioAttributes);

// 1秒后取消振动
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
    public void run() {
        Log.e("TAG", "Cancel Vibration");
        vib.cancel();
    }
}, 1000);

存在问题的代码(振动持续20秒,未被1秒后的cancel终止)

// 创建Vibrator实例
Vibrator vib = (Vibrator) MainActivity.this.getSystemService(Context.VIBRATOR_SERVICE);

AudioAttributes audioAttributes = new AudioAttributes.Builder()
    .setUsage(AudioAttributes.USAGE_GAME)
    .build();

// 启动20秒振动
vib.vibrate(20000, audioAttributes);

// ====== 新增代码 ======
vib.cancel(); // 尝试取消当前振动
vib.vibrate(20000, audioAttributes); // 启动新的20秒振动
// ====== 新增代码结束 ======

// 1秒后尝试取消振动
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
    public void run() {
        Log.e("TAG", "Cancel Vibration");
        vib.cancel();
    }
}, 1000);

问题原因

在SDK33这类高版本Android系统中,Vibrator的任务调度存在时序漏洞:当你连续调用vibrate()→cancel()→vibrate()时,系统还未完成第一次振动的初始化流程,就收到了cancel指令,紧接着又启动新振动,导致内部状态混乱,最终后续的cancel()无法正确绑定到新的振动任务上。

另外,直接传时长的vibrate()是旧API封装,在新系统中的状态管理不如显式使用VibrationEffect稳定。

解决方法

1. 显式使用VibrationEffect构建振动(推荐)

从Android O(API26)开始,官方推荐使用VibrationEffect构建振动指令,能精准控制振动状态,避免旧API的状态混乱问题:

Vibrator vib = (Vibrator) MainActivity.this.getSystemService(Context.VIBRATOR_SERVICE);
AudioAttributes audioAttributes = new AudioAttributes.Builder()
    .setUsage(AudioAttributes.USAGE_GAME)
    .build();

// 第一次振动
VibrationEffect firstEffect = VibrationEffect.createOneShot(20000, VibrationEffect.DEFAULT_AMPLITUDE);
vib.vibrate(firstEffect, audioAttributes);

// 取消并启动新振动
vib.cancel();
// 自定义新振动的时长/强度
VibrationEffect newEffect = VibrationEffect.createOneShot(20000, VibrationEffect.DEFAULT_AMPLITUDE);
vib.vibrate(newEffect, audioAttributes);

// 1秒后取消新振动
new Handler().postDelayed(() -> {
    Log.e("TAG", "Cancel New Vibration");
    vib.cancel();
}, 1000);

2. 增加微小延迟确保cancel生效

如果必须连续执行取消+重启操作,可以在cancel()后添加10ms左右的延迟,让系统完成状态清理后再启动新振动:

vib.cancel();
new Handler().postDelayed(() -> {
    vib.vibrate(20000, audioAttributes);
}, 10);

3. SDK31+使用带AudioAttributes的精准cancel

Android 12(SDK31)及以上版本,Vibrator新增了cancel(AudioAttributes)方法,可精准取消对应音频属性的振动任务,避免误操作其他振动:

// 仅取消指定AudioAttributes的振动
vib.cancel(audioAttributes);

前置注意事项

确保已在Manifest中声明振动权限,SDK23及以上还需动态申请权限:

<uses-permission android:name="android.permission.VIBRATE" />

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 20:30:38