使用AudioPlayers与Future.wait播放音效时Flutter应用崩溃求助
Flutter音效播放多次后崩溃问题排查与解决
问题描述
我需要创建List<Future<void>>管理音效播放任务,遍历事件列表(如"sword"类型)并映射为对应音效播放操作。为实现随机播放间隔,每个任务用Future.delayed包裹,设置30-100毫秒随机延迟,最后通过Future.wait批量执行。前几次运行音效播放正常,但执行4次后应用直接崩溃,怀疑是资源管理或audioplayers API使用不当导致。
代码实现
音效播放逻辑
_playActionEventSounds() async { if (widget.log.isNotEmpty) { final lastRound = widget.log.map((e) => e.round).reduce(max); final lastActionEvents = widget.log.where((actionEvent) => actionEvent.round == lastRound); final List<Future<void>> eventSounds = lastActionEvents.map((actionEvent) async { if (actionEvent.format == "sword") { return Future.delayed(Duration(milliseconds: next(30, 100)), () => _soundPlayer.punch()); } if (actionEvent.format == "damage") { return Future.delayed(Duration(milliseconds: next(30, 100)), () => _soundPlayer.pain()); } return Future.value(null); }).toList(); await Future.wait(eventSounds); } }
SoundPlayer类
import 'package:audioplayers/audioplayers.dart'; class SoundPlayer { Future<void> punch() async { final player = AudioPlayer(); player.setReleaseMode(ReleaseMode.stop); return await player.play(AssetSource("sounds/punch.wav")); } Future<void> pain() async { final player = AudioPlayer(); player.setReleaseMode(ReleaseMode.stop); return await player.play(AssetSource("sounds/pain.wav")); } }
错误日志
I/flutter (28346): Unexpected platform error: MediaPlayer error with what:MEDIA_ERROR_UNKNOWN {what:1} extra:MEDIA_ERROR_UNKNOWN {extra:-19} E/MediaPlayerNative(28346): pause called in state 0, mPlayer(0xb400007a92646810) E/MediaPlayerNative(28346): error (-38, 0) E/MediaPlayerNative(28346): Attempt to call getDuration in wrong state: mPlayer=0xb400007a92646810, mCurrentState=0 E/MediaPlayerNative(28346): error (-38, 0) E/MediaPlayerNative(28346): stop called in state 0, mPlayer(0xb400007a92646810) E/MediaPlayerNative(28346): error (-38, 0) E/MediaPlayerNative(28346): prepareAsync called in state 0, mPlayer(0xb400007a92646810) D/AndroidRuntime(28346): Shutting down VM E/AndroidRuntime(28346): FATAL EXCEPTION: main E/AndroidRuntime(28346): Process: com.example.app, PID: 28346 E/AndroidRuntime(28346): java.lang.IllegalStateException E/AndroidRuntime(28346): at android.media.MediaPlayer._prepare(Native Method) E/AndroidRuntime(28346): at android.media.MediaPlayer.prepare(MediaPlayer.java:1313) E/AndroidRuntime(28346): at xyz.luan.audioplayers.player.MediaPlayerPlayer.prepare(MediaPlayerPlayer.kt:89) E/AndroidRuntime(28346): at xyz.luan.audioplayers.player.WrappedPlayer.stop(WrappedPlayer.kt:185) E/AndroidRuntime(28346): at xyz.luan.audioplayers.player.WrappedPlayer.onCompletion(WrappedPlayer.kt:248) E/AndroidRuntime(28346): at xyz.luan.audioplayers.player.MediaPlayerPlayer.createMediaPlayer$lambda-5$lambda-1(MediaPlayerPlayer.kt:17) E/AndroidRuntime(28346): at xyz.luan.audioplayers.player.MediaPlayerPlayer.$r8$lambda$3fK1i48Yert5dbg2Q8ZiB5tiKHg(Unknown Source:0) E/AndroidRuntime(28346): at xyz.luan.audioplayers.player.MediaPlayerPlayer$$ExternalSyntheticLambda1.onCompletion(Unknown Source:2) E/AndroidRuntime(28346): at android.media.MediaPlayer$EventHandler.handleMessage(MediaPlayer.java:3559) E/AndroidRuntime(28346): at android.os.Handler.dispatchMessage(Handler.java:106) E/AndroidRuntime(28346): at android.os.Looper.loopOnce(Looper.java:201) E/AndroidRuntime(28346): at android.os.Looper.loop(Looper.java:288) E/AndroidRuntime(28346): at android.app.ActivityThread.main(ActivityThread.java:7842) E/AndroidRuntime(28346): at java.lang.reflect.Method.invoke(Native Method) E/AndroidRuntime(28346): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) E/AndroidRuntime(28346): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003) I/Process (28346): Sending signal. PID: 28346 SIG: 9 Lost connection to device.
解决方法
1. 修复AudioPlayer资源泄漏问题
当前代码每次播放都新建AudioPlayer实例,且未主动释放资源,多次调用后会耗尽系统媒体播放器资源,触发状态异常。
2. 优化SoundPlayer类,复用播放器实例
改为为每种音效维护单例播放器,并在播放完成后重置状态,页面销毁时释放资源:
import 'package:audioplayers/audioplayers.dart'; class SoundPlayer { final AudioPlayer _punchPlayer = AudioPlayer(); final AudioPlayer _painPlayer = AudioPlayer(); Future<void> punch() async { try { await _punchPlayer.setSource(AssetSource("sounds/punch.wav")); await _punchPlayer.play(); // 播放完成后重置状态,避免下次播放出错 _punchPlayer.onPlayerComplete.listen((_) { _punchPlayer.stop(); _punchPlayer.seek(Duration.zero); }); } catch (e) { print("punch音效播放失败: $e"); } } Future<void> pain() async { try { await _painPlayer.setSource(AssetSource("sounds/pain.wav")); await _painPlayer.play(); _painPlayer.onPlayerComplete.listen((_) { _painPlayer.stop(); _painPlayer.seek(Duration.zero); }); } catch (e) { print("pain音效播放失败: $e"); } } // 在页面销毁时调用,释放所有播放器资源 void dispose() { _punchPlayer.dispose(); _painPlayer.dispose(); } }
3. 修正随机延迟生成逻辑
确保随机数生成正确,使用dart:math的Random类:
import 'dart:math'; final random = Random(); // 生成30-100毫秒的随机延迟 int getRandomDelay() => random.nextInt(71) + 30; // 71 = 100 - 30 + 1
4. 捕获异常避免崩溃扩散
在播放方法中添加异常捕获,防止单个音效播放失败导致整个应用崩溃。
内容的提问来源于stack exchange,提问作者xetra11
相关产品推荐
相关产品推荐

