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

如何解决Flutter快速点击按钮时的音频播放错误?

解决快速点击音频播放按钮的中断错误

问题背景

我用以下代码实现点击按钮播放音频:

AudioPlayer player = AudioPlayer();
Future<void> playSound({required String soundStr}) async {
 player.setAsset(soundStr);
 player.play();
}

但快速点击按钮时会触发加载中断错误,添加player.stop();后问题依旧,错误日志如下:

E/flutter ( 4312): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(abort, Loading interrupted, null, null)
E/flutter ( 4312): #0      AudioPlayer._setPlatformActive.checkInterruption (package:just_audio/just_audio.dart:1236:7)
E/flutter ( 4312): #1      AudioPlayer._setPlatformActive.setPlatform (package:just_audio/just_audio.dart:1347:11)
E/flutter ( 4312): <asynchronous suspension>
E/flutter ( 4312): 
E/flutter ( 4312): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(abort, Loading interrupted, null, null)
E/flutter ( 4312): 

无效尝试

给异步操作添加await后,错误类型改变但问题仍存在:

Future<void> playSound({required String soundStr}) async {
 await player.setAsset(soundStr);
 await player.play();
}

新错误日志:

E/flutter (21654): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Connection aborted
E/flutter (21654): #0      AudioPlayer._load (package:just_audio/just_audio.dart:843:11)
E/flutter (21654): <asynchronous suspension>
E/flutter (21654): #1      AudioPlayer.load (package:just_audio/just_audio.dart:770:14)
E/flutter (21654): <asynchronous suspension>
E/flutter (21654): #2      AudioPlayer.setAudioSource (package:just_audio/just_audio.dart:745:18)
E/flutter (21654): <asynchronous suspension>
E/flutter (21654): #3      playSound (package:super_pinoy_quiz/common/generic_methods.dart:396:3)
E/flutter (21654): <asynchronous suspension>
E/flutter (21654): 

测试过just_audio: ^0.9.29和audioplayers: ^1.1.1两个包,均出现同类问题。

有效解决方案

1. 播放状态锁(通用方案)

通过布尔变量标记播放状态,避免重复触发异步操作:

bool _isProcessing = false;
AudioPlayer player = AudioPlayer();

Future<void> playSound({required String soundStr}) async {
  // 正在处理播放请求时直接返回
  if (_isProcessing) return;
  _isProcessing = true;

  try {
    // 先终止当前播放并重置进度
    await player.stop();
    await player.seek(Duration.zero);
    // 加载并播放音频
    await player.setAsset(soundStr);
    await player.play();
  } catch (e) {
    // 捕获错误避免崩溃
    print("播放异常: $e");
  } finally {
    // 无论成功失败,都解锁状态
    _isProcessing = false;
  }
}

2. 音频预加载(针对audioplayers包)

利用AudioCache提前缓存音频,减少重复加载的开销:

import 'package:audioplayers/audioplayers.dart';

final AudioCache _audioCache = AudioCache();
bool _isPlaying = false;

Future<void> playSound({required String soundStr}) async {
  if (_isPlaying) return;
  _isPlaying = true;

  try {
    final player = await _audioCache.play(soundStr);
    // 监听播放完成事件,释放状态锁
    player.onPlayerComplete.listen((_) => _isPlaying = false);
  } catch (e) {
    print("播放异常: $e");
    _isPlaying = false;
  }
}

3. 点击防抖(控制触发频率)

通过定时器限制短时间内的重复点击:

import 'dart:async';

AudioPlayer player = AudioPlayer();
Timer? _debounceTimer;

void onButtonTap(String soundStr) {
  // 取消上次未执行的定时器
  _debounceTimer?.cancel();
  // 300毫秒后执行播放逻辑,可根据需求调整时长
  _debounceTimer = Timer(const Duration(milliseconds: 300), () {
    _playSound(soundStr);
  });
}

Future<void> _playSound(String soundStr) async {
  try {
    await player.stop();
    await player.setAsset(soundStr);
    await player.play();
  } catch (e) {
    print("播放异常: $e");
  }
}

// 记得在组件销毁时清理定时器和播放器
@override
void dispose() {
  _debounceTimer?.cancel();
  player.dispose();
  super.dispose();
}

内容的提问来源于stack exchange,提问作者Mr. Tacio

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 00:20:53