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

使用just_audio动态创建播放列表时断言失败问题求助

问题分析与修复方案

核心问题原因

断言失败的本质是你传入的initialIndex不在播放列表的有效索引范围内,或者播放列表初始化/更新逻辑存在问题,导致内部索引集合未正确同步。

你的代码里的几个关键问题:

  1. 播放列表初始化与更新方式错误:
    你先创建空的ConcatenatingAudioSource,再通过playlist.children.add()添加元素,但ConcatenatingAudioSource的children是不可变列表(动态添加后未触发内部状态更新),导致组件无法识别新添加的子元素,索引集合仍然是空的。
  2. 索引越界风险:
    调用setAudioSource(playlist, initialIndex: index)时,index对应的是songList的索引,但如果songList和playlist.children的长度不一致(比如初始化时songList还没加载完成),就会导致索引无效。
  3. build方法内重复初始化:
    在build里每次都重新创建playlist并添加元素,build会因状态变化多次执行,可能导致播放列表状态混乱,甚至出现元素未正确添加的情况。

具体修复步骤

1. 正确构建动态播放列表

不要先创建空列表再添加元素,而是直接用songList生成完整的children列表,一次性初始化ConcatenatingAudioSource:

// 移除原来的late声明和getPlaylistAutomatic方法
// 改为在合适的时机(比如initState)构建播放列表
@override
void initState() {
  super.initState();
  _buildPlaylist();
}

void _buildPlaylist() {
  final children = songList.map((elem) => AudioSource.uri(Uri.parse(elem.uri!))).toList();
  playlist = ConcatenatingAudioSource(
    useLazyPreparation: true,
    shuffleOrder: DefaultShuffleOrder(),
    children: children,
  );
}

2. 确保initialIndex有效

调用setAudioSource前,先检查index是否在0到playlist.children.length - 1范围内:

// 修改PlayerController的playSongconCat方法
playSongconCat(String? uri, ConcatenatingAudioSource playlist, int index) async {
  print("Concatenating playlist -- ${playlist.children}");
  if (!getPlayingStatus()) {
    try {
      // 检查索引有效性
      if (index < 0 || index >= playlist.children.length) {
        print("Invalid initial index: $index, using 0 instead");
        index = 0;
      }
      await audioPlayer.setAudioSource(playlist, initialIndex: index);
      await audioPlayer.setLoopMode(LoopMode.all); // 设置循环
      await audioPlayer.play();
      putPlayingStatus(true);
    } catch (excep) {
      print("Error while playing concatenation: ${excep.toString()}");
    }
  }
}

3. 避免在build内重复初始化播放列表

把播放列表的构建移到initState(如果songList是初始化时就有的),或者在songList更新时重新构建(比如用FutureBuilder监听songList的加载状态),不要每次build都重新创建:

@override
Widget build(BuildContext context) {
  // 移除build内的playlist初始化和getPlaylistAutomatic调用
  // 如果songList是异步加载的,用FutureBuilder处理
  return FutureBuilder<List<Song>>(
    future: loadSongList(), // 你的加载歌曲列表的方法
    builder: (context, snapshot) {
      if (snapshot.hasData) {
        songList = snapshot.data!;
        _buildPlaylist();
        playerControllers.playSongconCat(songList[currentIndex].uri, playlist, currentIndex);
        return // 你的页面组件;
      } else {
        return CircularProgressIndicator();
      }
    },
  );
}

4. 修复硬编码播放列表后的崩溃问题

硬编码时播放完第一首崩溃,大概率是因为播放列表末尾的音频资源有问题,或者循环模式未正确设置。确保所有音频URI有效,并且在setAudioSource后明确设置LoopMode.all。


额外注意事项

  • 确保songList中的每个elem.uri都是有效的本地文件URI(比如file:///storage/emulated/0/...),无效URI会导致子音频源加载失败,间接影响索引有效性。
  • 如果需要动态增删播放列表元素,使用ConcatenatingAudioSource提供的add/remove方法(不是直接操作children列表),这些方法会触发内部状态更新:
    await playlist.add(AudioSource.uri(Uri.parse(newUri)));
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 19:13:17