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

Android 10中MediaMetadataRetriever抛出异常该如何解决?

问题根因

Android 10(API 级别 29)引入分区存储机制后,即便在Manifest中配置了android:requestLegacyExternalStorage="true",MediaMetadataRetriever.setDataSource(String path)方法对共享存储内的非应用自有媒体文件的访问依然会被系统限制,直接传入文件路径会触发IllegalArgumentException异常。另外你原代码未主动释放MediaMetadataRetriever资源,也会引发内存泄漏、偶发访问冲突等问题。

解决方案

方案1:使用Content Uri作为数据源(推荐)

从MediaStore查询音频文件时,不要只存文件路径,同时保存MediaStore返回的content://格式的Uri,使用带Context参数的setDataSource方法加载,适配分区存储规则。
修改后代码如下:

private Bitmap getAlbumImage(Context context, Uri audioUri) {
    MediaMetadataRetriever mmr = new MediaMetadataRetriever();
    try {
        mmr.setDataSource(context, audioUri);
        byte[] data = mmr.getEmbeddedPicture();
        if (data != null) {
            return BitmapFactory.decodeByteArray(data, 0, data.length);
        }
    } catch (IOException | IllegalArgumentException e) {
        // 异常捕获避免崩溃,损坏的音频文件直接返回空即可
        e.printStackTrace();
    } finally {
        // 必须主动释放资源
        try {
            mmr.release();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return null;
}

方案2:通过文件描述符加载(仅适用于仍需使用文件路径的场景)

如果业务逻辑必须使用文件路径,可以先打开文件的文件描述符再传给MediaMetadataRetriever:

private Bitmap getAlbumImage(String path) {
    MediaMetadataRetriever mmr = new MediaMetadataRetriever();
    FileInputStream fis = null;
    try {
        fis = new FileInputStream(path);
        mmr.setDataSource(fis.getFD());
        byte[] data = mmr.getEmbeddedPicture();
        if (data != null) {
            return BitmapFactory.decodeByteArray(data, 0, data.length);
        }
    } catch (IOException | IllegalArgumentException e) {
        e.printStackTrace();
    } finally {
        try {
            mmr.release();
            if (fis != null) {
                fis.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return null;
}

优化建议

你可以直接从MediaStore查询音频对应的专辑封面Uri,不需要自行解析媒体文件,稳定性和性能更高:

  1. 查询音频时同时获取MediaStore.Audio.Media.ALBUM_ID字段
  2. 拼接专辑封面Uri:Uri albumArtUri = ContentUris.withAppendedId(Uri.parse("content://media/external/audio/albumart"), albumId);
  3. 直接加载该Uri即可得到专辑封面
注意事项
  • 必须提前申请对应存储权限:Android 10及以下动态申请READ_EXTERNAL_STORAGE权限,Android 13及以上动态申请READ_MEDIA_AUDIO权限,权限未通过时不要执行媒体文件访问操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 09:06:04