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

Flutter audioplayers 3.0.1 Windows端热重启后音频无法播放问题

问题描述

我在Windows和原生Android平台使用版本为3.0.1的audioplayers插件。Android端一切运行正常,但Windows端存在问题:

正常情况

Windows和Android端均可正常播放MP3音频文件。

异常情况

仅在Windows端,执行Hot Restart后再次播放同一音频文件时,触发以下错误:

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: FileSystemException: Cannot open file, path = 'C:\Users\<mypath>.mp3' (OS Error: Der Prozess kann nicht auf die Datei zugreifen, da sie von einem anderen Prozess verwendet wird.

, errno = 32)
#0      _File.open.<anonymous closure> (dart:io/file_impl.dart:356:9)
<asynchronous suspension>
#1      AudioCache.fetchToMemory (package:audioplayers/src/audio_cache.dart:80:5)
<asynchronous suspension>
#2      AudioCache.load (package:audioplayers/src/audio_cache.dart:101:31)
<asynchronous suspension>
#3      AudioPlayer.setSourceAsset (package:audioplayers/src/audioplayer.dart:249:17)
<asynchronous suspension>
#4      AudioPlayer.play (package:audioplayers/src/audioplayer.dart:131:5)
<asynchronous suspension>

我的播放器调用方式:

_player.play(AssetSource('<file>.mp3'));

已确认在组件销毁时调用了_player的dispose方法。

请问我是否错误使用了播放器?Hot Restart是否存在未知的特殊机制?


问题分析与解决方案

问题原因

你没有错误使用播放器,问题出在Windows平台下Hot Restart的特殊机制:

  • Hot Restart仅重启Dart虚拟机,Windows原生进程(你的Flutter应用.exe)并未终止。
  • 虽然你在Dart层调用了dispose,但Windows原生侧的音频播放实例可能未及时释放MP3文件的句柄,导致文件被占用,再次播放时无法打开。

解决方案

  1. 完善资源释放流程
    在调用dispose前先调用release方法,确保原生侧主动释放资源和文件句柄:

    await _player.release();
    await _player.dispose();
    

    必须使用await确保异步释放操作完成。

  2. 全局单例管理AudioPlayer
    避免重复创建实例,全局维护一个AudioPlayer实例,减少资源泄漏风险:

    import 'package:audioplayers/audioplayers.dart';
    
    class AudioManager {
      static final AudioPlayer _player = AudioPlayer();
    
      static AudioPlayer get player => _player;
    
      static Future<void> cleanUp() async {
        await _player.release();
        await _player.dispose();
      }
    }
    

    可以通过监听应用生命周期,在应用即将退出或Hot Restart前调用AudioManager.cleanUp():

    WidgetsBinding.instance.addObserver(LifecycleObserver());
    
    class LifecycleObserver extends WidgetsBindingObserver {
      @override
      void didChangeAppLifecycleState(AppLifecycleState state) {
        if (state == AppLifecycleState.detached) {
          AudioManager.cleanUp();
        }
      }
    }
    
  3. 临时文件播放备选方案
    将Asset中的MP3复制到临时目录后播放,避免原Asset文件被锁定:

    import 'dart:io';
    import 'package:flutter/services.dart';
    import 'package:path_provider/path_provider.dart';
    import 'package:audioplayers/audioplayers.dart';
    
    Future<void> playAudioFromTemp(String assetPath) async {
      // 读取Asset文件
      final byteData = await rootBundle.load(assetPath);
      // 获取临时目录
      final tempDir = await getTemporaryDirectory();
      final tempFile = File('${tempDir.path}/audio_temp.mp3');
      // 写入临时文件
      await tempFile.writeAsBytes(byteData.buffer.asUint8List());
      // 播放临时文件
      await AudioManager.player.play(FileSource(tempFile.path));
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 15:40:38