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

Xamarin Android无法播放外置SD卡中应用外部存储的MP3文件

解决Xamarin Android Service中外置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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 21:47:27