Android 10(API29) MediaMetadataRetriever.setDataSource非法参数异常求助
Android 10下MediaMetadataRetriever.setDataSource抛出IllegalArgumentException的解决方案
这个问题我之前也碰到过,核心原因是Android 10(API 29)引入的Scoped Storage机制限制了直接访问外部存储的文件路径,而你使用的setDataSource(String uri)方法如果传入的是外部文件的绝对路径,在Android 10上就会触发IllegalArgumentException。
问题分析
你的代码在Android 9及以下、Android 11+能正常运行的原因:
- Android 9及以下没有Scoped Storage限制,直接访问文件路径是允许的;
- Android 11+虽然也有Scoped Storage,但系统对
setDataSource(String)做了兼容处理,不过官方还是推荐使用更合规的方式。
解决方案
推荐使用兼容所有版本的重载方法,根据你的Uri类型选择:
情况1:使用MediaStore返回的Content Uri(推荐)
如果你的音频Uri是从MediaStore获取的content://开头的Uri,直接使用带Context的重载方法即可,这个方法从API 14就支持,完美兼容所有版本:
private byte[] getAlbumArt(Context context, Uri audioUri) { MediaMetadataRetriever retriever = new MediaMetadataRetriever(); try { // 传入Context和Content Uri,替代直接传路径字符串 retriever.setDataSource(context, audioUri); return retriever.getEmbeddedPicture(); } catch (Exception e) { e.printStackTrace(); return null; } finally { retriever.release(); } }
情况2:必须使用文件路径(比如应用私有目录)
如果你的音频文件在应用私有目录(getFilesDir()或getExternalFilesDir()),可以通过FileDescriptor来设置数据源:
private byte[] getAlbumArt(String filePath) { MediaMetadataRetriever retriever = new MediaMetadataRetriever(); FileInputStream fis = null; try { File audioFile = new File(filePath); fis = new FileInputStream(audioFile); retriever.setDataSource(fis.getFD()); return retriever.getEmbeddedPicture(); } catch (IOException | IllegalArgumentException e) { e.printStackTrace(); return null; } finally { try { if (fis != null) { fis.close(); } } catch (IOException e) { e.printStackTrace(); } retriever.release(); } }
额外注意事项
- 权限方面:在API 33之前需要申请
READ_EXTERNAL_STORAGE权限,API 33及以上可以申请更细分的READ_MEDIA_AUDIO权限; - 尽量避免直接使用文件路径,优先使用
Content Uri,符合Android存储规范,减少版本兼容问题。
内容的提问来源于stack exchange,提问作者Rami
相关产品推荐
相关产品推荐

