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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 04:43:24