音频播放器切换音源报错:Bad state: Cannot fire new event. 求解决
解决音频连续播放时的"Bad state"错误
问题根源
这个错误本质是播放器的事件控制器在派发事件(比如completed状态回调)的过程中,被同步触发了新的播放器操作(setAudioSource),导致状态冲突——控制器无法在当前事件未处理完成时响应新的事件请求。
具体修复方案
1. 延迟执行下一曲目操作
不要在playbackEventStream的回调里同步调用切换逻辑,把操作放到微任务队列,让当前事件处理完成后再执行新操作:
audioPlayer.playbackEventStream.listen((event) { if (event.processingState == ProcessingState.completed) { // 用微任务队列延迟执行,避开当前事件处理周期 Future.microtask(() => handleNextItem()); } });
2. 确保播放器状态就绪后再设置新源
在切换曲目的方法里,先让播放器进入稳定状态,再执行setAudioSource:
Future<void> handleNextItem() async { // 先停止播放,确保播放器退出活跃状态 await _audioPlayer.stop(); // 再设置新音频源并播放 await _audioPlayer.setAudioSource(AudioSource.uri(Uri.parse(audioUrl))); await _audioPlayer.play(); }
3. 避免重复监听事件流
检查代码中是否多次调用playbackEventStream.listen,多个监听器会导致handleNextItem被重复触发,引发冲突。确保只监听一次,或者在重新监听前取消旧的监听器:
// 保存监听器对象,方便后续取消 StreamSubscription? _playbackSubscription; // 初始化监听 void initPlayerListener() { _playbackSubscription?.cancel(); _playbackSubscription = audioPlayer.playbackEventStream.listen((event) { if (event.processingState == ProcessingState.completed) { Future.microtask(() => handleNextItem()); } }); }
4. 用拼接音频源实现无缝播放(推荐)
如果使用的是just_audio这类支持列表播放的库,直接用ConcatenatingAudioSource自动处理曲目切换,无需手动监听状态:
// 初始化时创建拼接播放源 final _playlist = ConcatenatingAudioSource(children: []); await _audioPlayer.setAudioSource(_playlist); // 添加新曲目到列表,播放器会自动无缝续播 _playlist.add(AudioSource.uri(Uri.parse(audioUrl)));
额外防护措施
添加状态锁,防止handleNextItem被重复调用:
bool _isSwitchingTrack = false; Future<void> handleNextItem() async { if (_isSwitchingTrack) return; _isSwitchingTrack = true; try { // 获取下一曲目URL的逻辑 final audioUrl = await fetchNextAudioFromBackend(); await _audioPlayer.stop(); await _audioPlayer.setAudioSource(AudioSource.uri(Uri.parse(audioUrl))); await _audioPlayer.play(); } finally { _isSwitchingTrack = false; } }
内容的提问来源于stack exchange,提问作者ChengguiS.
相关产品推荐
相关产品推荐

