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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 01:20:37