Flutter中使用just_audio实现音频连续播放问题求助
问题描述
需要实现10-15个从服务器获取的动态音频连续播放,使用just_audio包的ConcatenatingAudioSource方案,但点击播放按钮后无任何反应,日志也没有输出。以下是相关代码:
初始化代码
late AudioPlayer _audioPlayer; List<AudioPlayer> players = []; ConcatenatingAudioSource concatenatingAudioSource = ConcatenatingAudioSource(children: []); @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((timeStamp) { final state = ref.watch(homeController); state.ayahList.forEach((element) async { final player = AudioPlayer(); await player.setUrl('https://example.com/$element.mp3'); players.add(player); }); final audioSources = players .map((player) => player.audioSource ?? AudioSource.uri(Uri())) .toList(); concatenatingAudioSource = ConcatenatingAudioSource(children: audioSources); _audioPlayer = AudioPlayer()..setAudioSource(concatenatingAudioSource); }); }
UI代码
@override Widget build(BuildContext context) { return StreamBuilder( stream: audioPlayer.playerStateStream, builder: (context, snapshot) { final playerState = snapshot.data; final processingState = playerState?.processingState; final playing = playerState?.playing; if (!(playing ?? false)) { return IconButton( onPressed: () => audioPlayer.play(), icon: const Icon(Icons.play_arrow_rounded)); } else if (processingState != ProcessingState.completed) { return IconButton( onPressed: () => audioPlayer.pause(), icon: const Icon(Icons.pause_rounded)); } return const Icon(Icons.play_arrow_rounded); }); }
问题排查与修复方案
1. 异步循环导致数据源为空
forEach中的async回调不会阻塞后续代码执行,当你生成audioSources列表时,players还是空数组——因为await player.setUrl还没执行完毕。这会让ConcatenatingAudioSource的子项全是无效的AudioSource.uri(Uri()),自然无法播放。
修复:改用for循环确保所有音频源加载完成后再创建拼接源,同时不需要为每个音频单独创建AudioPlayer:
@override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { final state = ref.watch(homeController); final audioSources = <AudioSource>[]; for (final element in state.ayahList) { audioSources.add(AudioSource.uri(Uri.parse('https://example.com/$element.mp3'))); } concatenatingAudioSource = ConcatenatingAudioSource(children: audioSources); _audioPlayer = AudioPlayer(); // 捕获异常排查问题 await _audioPlayer.setAudioSource(concatenatingAudioSource).catchError((err) { print('音频源设置失败: $err'); }); }); }
2. 播放器实例引用不匹配
UI代码中使用的audioPlayer和初始化的_audioPlayer不是同一个实例,导致点击播放时操作的是错误的对象。
修复:统一变量名,将UI中的audioPlayer替换为_audioPlayer:
@override Widget build(BuildContext context) { return StreamBuilder( stream: _audioPlayer.playerStateStream, builder: (context, snapshot) { final playerState = snapshot.data; final processingState = playerState?.processingState; final playing = playerState?.playing; if (!(playing ?? false)) { return IconButton( onPressed: () => _audioPlayer.play(), icon: const Icon(Icons.play_arrow_rounded)); } else if (processingState != ProcessingState.completed) { return IconButton( onPressed: () => _audioPlayer.pause(), icon: const Icon(Icons.pause_rounded)); } return const Icon(Icons.play_arrow_rounded); }); }
3. 未处理异常
原代码没有捕获setAudioSource可能抛出的异常(比如URL无效、网络错误),导致无法排查问题。添加异常捕获后可以直接在日志中看到错误原因。
4. 冗余的多播放器实例
ConcatenatingAudioSource的设计就是让单个AudioPlayer实例播放多个音频源,不需要为每个音频单独创建AudioPlayer,这会造成资源浪费。
内容的提问来源于stack exchange,提问作者Tanjim ahmed
相关产品推荐
相关产品推荐

