Xamarin Android无法播放外置SD卡中应用外部存储的MP3文件
你已经搞定了权限验证和文件访问的基础问题,但MediaPlayer的Prepare()抛出异常,核心原因大概率是数据源的设置方式不符合Android存储规范,或者没处理好MediaPlayer的异步初始化逻辑。下面给你几个针对性的解决方案:
1. 改用ContentResolver生成Uri设置数据源
对于外置SD卡上的应用专属目录(Android/data/你的包名/files/),虽然你有权限直接读取,但MediaPlayer直接用文件路径或文件描述符的方式,可能会被Scoped Storage的隐性限制拦截。改用ContentResolver生成的Uri传递数据源是更可靠的方式:
// 替换你循环中的播放逻辑 foreach (string fileName in System.IO.Directory.GetFiles(songFolder, "*.*", SearchOption.AllDirectories)) { // 先释放旧的MediaPlayer实例,避免资源泄漏 player?.Release(); player = new MediaPlayer(); // 生成对应文件的Uri var fileUri = Android.Net.Uri.FromFile(new Java.IO.File(fileName)); // 通过ApplicationContext和Uri设置数据源 player.SetDataSource(this.ApplicationContext, fileUri); // 改用异步Prepare,避免阻塞Service主线程 player.PrepareAsync(); // 设置准备完成监听,确认就绪后再播放 player.Prepared += (s, e) => { player.Start(); }; // 添加错误监听,方便排查具体问题 player.Error += (s, e) => { Log.Error("MediaPlayerError", $"错误码: {e.What}, 附加信息: {e.Extra}"); player.Release(); player = null; }; break; }
2. 规范MediaPlayer的资源管理
你当前每次循环都会新建MediaPlayer实例,但没有释放旧实例,这可能导致音频资源泄漏,甚至影响新实例的初始化。记得在创建新实例前,先调用Release()清理旧实例。
3. 完善异常日志排查
你现在的异常处理只是x.ToString(),完全看不到具体错误细节。建议替换成日志输出,方便精准定位问题:
catch (Exception x) { Log.Error("PlaybackError", x.ToString()); Toast.MakeText(this, $"播放失败: {x.Message}", ToastLength.Long).Show(); }
4. 验证文件本身的可用性
虽然你能通过BinaryReader读取文件内容,但还是要确认MP3文件本身是否完整、编码是否被Android MediaPlayer支持。可以尝试将文件复制到应用内部存储目录,用同样的播放逻辑测试,如果能正常播放,说明问题确实出在外置SD卡的数据源传递方式上。
为什么原有方式失效?
Android 10及以上的Scoped Storage机制,即使是应用专属的外部存储目录,直接使用文件路径或文件描述符给MediaPlayer时,系统可能会限制底层的文件访问权限。而通过ContentResolver生成的Uri,系统会自动处理权限验证,更符合现代Android的存储规范。
内容的提问来源于stack exchange,提问作者John

