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

Flutter中Just Audio Background切换页面音频停止问题求助

解决just_audio_background后台播放与歌曲切换问题

问题分析

  • 导航离开播放页面时,页面dispose方法销毁了AudioPlayer实例,直接导致后台播放停止、通知消失。
  • 移除_player.dispose()后,旧播放器实例未被销毁,新页面创建的播放器与旧实例冲突,无法正常切换歌曲。

解决方案

1. 全局共享播放器实例

用单例模式创建全局播放器,让所有页面共用同一个实例,避免重复创建和销毁:

// 全局单例播放器
class AudioPlayerSingleton {
  static final AudioPlayer instance = AudioPlayer();
  AudioPlayerSingleton._();
}

// 在AudioPlayer3State中使用单例
class AudioPlayer3State extends State<AudioPlayer3> {
  late final AudioPlayer _player = AudioPlayerSingleton.instance;
  // ... 其他代码
}

2. 调整播放器销毁时机

全局播放器不能在页面销毁时释放,改为在应用退出时才销毁:

void main() async {
  // 初始化just_audio_background(仅需调用一次)
  await JustAudioBackground.init(
    androidNotificationChannelId: 'com.ryanheise.bg_demo.channel.audio',
    androidNotificationChannelName: 'Audio playback',
    androidNotificationOngoing: true,
  );
  runApp(const MyApp());

  // 监听应用生命周期,退出时销毁播放器
  WidgetsBinding.instance.addObserver(LifecycleObserver(
    onExit: () => AudioPlayerSingleton.instance.dispose(),
  ));
}

class LifecycleObserver extends WidgetsBindingObserver {
  final VoidCallback onExit;
  LifecycleObserver({required this.onExit});

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.detached) onExit();
  }
}

3. 修复音频源切换逻辑

打开新歌曲页面时,更新全局播放器的音频源,而非创建新播放器:

Future<void> _init() async {
  final session = await AudioSession.instance;
  // 改用音乐场景配置,适配后台播放的系统策略
  await session.configure(const AudioSessionConfiguration.music());

  // 移除旧监听避免重复回调
  _player.playbackEventStream.listen((event) {}, onError: (e, stack) {
    print('Stream error: $e');
  }).cancel();

  try {
    // 检查当前音频源是否需要更新
    final currentSource = _player.audioSource;
    bool needUpdate = false;
    if (currentSource == null) {
      needUpdate = true;
    } else if (currentSource is ConcatenatingAudioSource) {
      final currentTitle = (currentSource.children.first.tag as MediaItem).title;
      needUpdate = currentTitle != widget.songTitleString;
    }
    if (needUpdate) await _player.setAudioSource(_playlist);
  } catch (e, stack) {
    print('Load playlist error: $e');
    print(stack);
  }
}

4. 修改页面dispose逻辑

因为播放器是全局的,页面销毁时不再调用_player.dispose():

@override
void dispose() {
  // 仅清理页面自身的资源,不要销毁全局_player
  super.dispose();
}

额外优化

  • 确保JustAudioBackground.init()在应用启动时调用一次即可,无需在每个页面重复初始化。
  • 音频会话配置使用AudioSessionConfiguration.music(),相比speech更符合音乐后台播放的系统优先级。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 02:39:57