Plugin.SimpleAudioPlayer切换音频时自动释放无法连续播放问题
问题描述
切换音频文件时音频播放器会被自动释放。开发的应用需要顺序播放shared\audio文件夹下的音频文件,目前首个音频文件可正常播放,但第一个音频播放结束后就会停止,无法继续播放后续内容。使用的是Plugin.SimpleAudioPlayer组件,实现代码如下:
public partial class MainPage : ContentPage { private ISimpleAudioPlayer audio; private int pagenum; public MainPage() { InitializeComponent(); } private void playaudio(int pgnum) { audio = CrossSimpleAudioPlayer.Current; audio.PlaybackEnded += cmdNextClicked; var stream = GetStreamFromFile(string.Concat("audio.w", (pgnum + 1).ToString(), ".mp3")); audio.Load(stream); audio.Play(); } Stream GetStreamFromFile(string filename) { var assembly = typeof(App).GetTypeInfo().Assembly; var stream = assembly.GetManifestResourceStream("App1." + filename); return stream; } private void cmdRunClicked(object sender, EventArgs e)// { playaudio(pagenum); } private void cmdStopClicked(object sender, EventArgs e)// { if (!(audio is null)) { audio.Stop(); } } private void cmdClicked(object sender, EventArgs e) { audio.Seek(audio.CurrentPosition + 30.0); } private void cmdNextClicked(object sender, EventArgs e) { pagenum++; lblPageNo.Text = pagenum.ToString(); playaudio(pagenum); } private void cmdPrevClicked(object sender, EventArgs e) { pagenum--; lblPageNo.Text = pagenum.ToString(); playaudio(pagenum); } }
错误原因
代码存在两个核心问题,直接导致播放中断、无法顺序切歌:
- 事件重复绑定引发逻辑混乱
每次调用playaudio都会执行一次audio.PlaybackEnded += cmdNextClicked,反复给同一个播放器实例绑定播放结束事件。第一次音频播放完成后,事件会被触发多次,pagenum会直接累加超过实际存在的文件索引,后续加载音频时拿到空流,播放直接终止。同时重复绑定事件会造成内存泄漏,播放器实例会被GC意外回收。 - 加载新音频前未重置播放器状态、释放资源
Plugin.SimpleAudioPlayer加载新音频流时,如果当前处于播放状态、旧的流资源未被释放,会触发播放器的内置回收逻辑,后续Play()调用无效,播放结束事件也不会正常触发。
此外代码缺少索引边界校验,当pagenum超出实际音频文件数量范围时,GetManifestResourceStream会返回null,调用Load方法直接抛出空引用异常,中断播放流程。
修复方案
按照以下规则修改代码即可:
- 将播放器实例初始化、事件绑定逻辑移到页面构造函数中,全生命周期只执行一次,禁止每次播放都重新赋值实例、重复绑定事件
- 每次加载新音频前,先调用
Stop()停止当前播放,释放旧的流资源 - 增加文件索引边界判断,避免加载不存在的音频
- 页面销毁时主动解绑事件、释放播放器资源
修复后的参考代码:
public partial class MainPage : ContentPage { private ISimpleAudioPlayer audio; private int pagenum; // 修改为实际存放的音频文件总数 private const int MaxAudioCount = 10; public MainPage() { InitializeComponent(); // 仅初始化一次播放器、绑定一次事件 audio = CrossSimpleAudioPlayer.Current; audio.PlaybackEnded += cmdNextClicked; } private void playaudio(int pgnum) { // 越界校验,避免加载不存在的文件 if (pgnum < 0 || pgnum >= MaxAudioCount) { pagenum = 0; } // 停止当前播放,释放旧资源 audio.Stop(); var stream = GetStreamFromFile(string.Concat("audio.w", (pgnum + 1).ToString(), ".mp3")); if (stream == null) return; audio.Load(stream); audio.Play(); } Stream GetStreamFromFile(string filename) { var assembly = typeof(App).GetTypeInfo().Assembly; var stream = assembly.GetManifestResourceStream("App1." + filename); return stream; } private void cmdRunClicked(object sender, EventArgs e) { playaudio(pagenum); } private void cmdStopClicked(object sender, EventArgs e) { audio?.Stop(); } private void cmdClicked(object sender, EventArgs e) { if (audio.IsPlaying) { audio.Seek(audio.CurrentPosition + 30.0); } } private void cmdNextClicked(object sender, EventArgs e) { pagenum++; lblPageNo.Text = pagenum.ToString(); playaudio(pagenum); } private void cmdPrevClicked(object sender, EventArgs e) { pagenum--; lblPageNo.Text = pagenum.ToString(); playaudio(pagenum); } // 页面销毁时释放资源 protected override void OnDisappearing() { base.OnDisappearing(); audio.Stop(); audio.PlaybackEnded -= cmdNextClicked; audio.Dispose(); } }
注意:需要确认嵌入资源的路径前缀
App1.和你的项目默认命名空间一致,否则会找不到音频流返回null。
内容的提问来源于stack exchange,提问作者Isherpal Singh
相关产品推荐
相关产品推荐

