Flutter assets_audio_player未释放实例时重复播放音频求助
解决assets_audio_player重复播放多轨的问题
核心原因
每次进入页面时,你通过AssetsAudioPlayer.newPlayer()创建了全新的播放器实例,而旧页面的实例未被释放(为了保留后台播放),导致多个实例同时播放同一音频,出现多轨叠加的情况。initState中尝试停止播放无效,是因为你操作的是新实例,旧实例仍在后台运行。
解决方案
方法1:使用全局单例播放器(推荐)
使用assets_audio_player默认的全局实例,而非每次创建新实例,这样无论页面如何跳转,始终只有一个播放器在运行,从根源避免多轨问题,同时保留后台播放能力。
修改后的完整代码:
import 'package:assets_audio_player/assets_audio_player.dart'; import 'package:flutter/material.dart'; class AudioPlayer6Page extends StatefulWidget { const AudioPlayer6Page({super.key}); @override State<AudioPlayer6Page> createState() => _AudioPlayer6PageState(); } class _AudioPlayer6PageState extends State<AudioPlayer6Page> { // 使用全局单例播放器,而非newPlayer创建新实例 final AssetsAudioPlayer assetsAudioPlayer = AssetsAudioPlayer(); @override void initState() { super.initState(); loadMedia(); } Future<void> loadMedia() async { try { // 先停止当前播放的音频,再加载新资源 await assetsAudioPlayer.stop(); await assetsAudioPlayer.open( Audio.network("https://s3.amazonaws.com/scifri-episodes/scifri20181123-episode.mp3"), autoStart: false, showNotification: true, ); } catch (t) { // 处理音频加载失败逻辑 debugPrint("音频加载失败: $t"); } } @override void dispose() { // 不要调用dispose,保留后台播放能力 print('dispose'); super.dispose(); } @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData(primarySwatch: Colors.blue), home: Scaffold( body: SingleChildScrollView( child: SizedBox( height: MediaQuery.of(context).size.height, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ const Center(child: Text('Another audio player')), StreamBuilder<bool>( stream: assetsAudioPlayer.isPlaying, initialData: false, builder: (context, snapshot) { final bool isPlaying = snapshot.data ?? false; return Center( child: IconButton( onPressed: () { isPlaying ? assetsAudioPlayer.pause() : assetsAudioPlayer.play(); }, icon: Icon( isPlaying ? Icons.pause : Icons.play_arrow, size: 50, ), ), ); }, ), ], ), ), ), ), ); } }
方法2:手动管理实例生命周期(适合多音频场景)
如果需要为不同页面创建独立播放器实例,可在页面初始化时主动停止所有正在运行的播放器实例,再加载新音频:
修改loadMedia方法如下:
Future<void> loadMedia() async { try { // 停止所有正在播放的播放器实例 await AssetsAudioPlayer.stopAll(); // 创建新实例并加载音频 assetsAudioPlayer = AssetsAudioPlayer.newPlayer(); await assetsAudioPlayer.open( Audio.network("https://s3.amazonaws.com/scifri-episodes/scifri20181123-episode.mp3"), autoStart: false, showNotification: true, ); } catch (t) { debugPrint("音频加载失败: $t"); } }
注意:这种方式会停止所有后台播放的音频,若需保留其他音频后台播放,需针对性管理实例引用。
关键修改点总结
- 避免重复创建播放器实例,优先使用全局单例
- 加载新音频前先停止当前播放(针对全局实例)
- 不要在
dispose中调用assetsAudioPlayer.dispose(),确保后台播放正常
内容的提问来源于stack exchange,提问作者Zeeshan Haider
相关产品推荐
相关产品推荐

