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

Flutter中如何更新AudioPlayer的音频源以播放不同歌曲?

解决Flutter AudioPlayer动态切换音频的问题

你的AudioPlayer组件仅在initState中初始化音频源,而initState只会在组件首次创建时执行一次。当父组件传递的audioPath参数变化时,组件没有响应这个变化去加载新的音频文件,导致始终播放初始音频。以下是修复方案:

关键修改点

  1. 修正State类的命名错误(原代码中createState返回的类型与实际定义的State类不匹配)
  2. 重写didUpdateWidget方法,监听audioPath参数变化,当参数更新时停止当前播放并加载新音频

修改后的完整代码

class AudioPlayer extends StatefulWidget {
  final String audioPath;

  const AudioPlayer({super.key, required this.audioPath});

  @override
  _AudioPlayerState createState() => _AudioPlayerState();
}

class _AudioPlayerState extends State<AudioPlayer> with WidgetsBindingObserver {
  final _player = AudioPlayer();

  @override
  void initState() {
    super.initState();
    ambiguate(WidgetsBinding.instance)!.addObserver(this);
    _initAudio(widget.audioPath);
  }

  Future<void> _initAudio(String audioPath) async {
    final session = await AudioSession.instance;
    await session.configure(const AudioSessionConfiguration.speech());
    
    // 停止当前播放并重置播放器状态
    await _player.stop();
    await _player.seek(Duration.zero);

    _player.playbackEventStream.listen((event) {},
        onError: (Object e, StackTrace stackTrace) {
      print('A stream error occurred: $e');
    });
    try {
      await _player.setAsset(audioPath);
      print("Audio asset is set: $audioPath");
      // 如果需要自动播放新音频,可添加以下代码
      // await _player.play();
    } catch (e) {
      print("Error loading audio source: $e");
    }
  }

  @override
  void didUpdateWidget(covariant AudioPlayer oldWidget) {
    super.didUpdateWidget(oldWidget);
    // 检查audioPath是否变化
    if (widget.audioPath != oldWidget.audioPath) {
      _initAudio(widget.audioPath);
    }
  }

  @override
  void dispose() {
    ambiguate(WidgetsBinding.instance)!.removeObserver(this);
    _player.dispose();
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.paused) {
      _player.stop();
    }
  }

  Stream<PositionData> get _positionDataStream =>
      Rx.combineLatest3<Duration, Duration, Duration?, PositionData>(
          _player.positionStream,
          _player.bufferedPositionStream,
          _player.durationStream,
          (position, bufferedPosition, duration) => PositionData(
              position, bufferedPosition, duration ?? Duration.zero));

  @override
  Widget build(BuildContext context) {
    // 保留你的原有build实现
    return ...;
  }
}

额外说明

  • 抽离_initAudio方法,复用初始化逻辑,避免代码冗余
  • 在加载新音频前先停止当前播放并重置进度,防止音频重叠或状态混乱
  • 如果需要点击按钮后自动播放新音频,可在_initAudio方法的setAsset成功后添加await _player.play()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 10:26:05