MediaStore获取音频异常:指定内部存储却读SD卡,INTERNAL_CONTENT_URI无效
问题分析与解决方案
我来帮你捋捋这个问题,你遇到的情况大概率是MediaStore的URI逻辑、路径匹配规则,加上Android存储权限的问题导致的,咱们一步步拆解:
1. 先搞懂EXTERNAL vs INTERNAL_CONTENT_URI的真实区别
很多人会误解这两个URI的作用:
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI并不是只指向外置SD卡,它实际覆盖了所有可挂载的外部存储介质——包括设备内置的主存储(也就是你说的“手机内部存储”)和外置SD卡。你之前读到SD卡内容,大概率是因为外置SD卡上也存在同名的/nexcox/voicerecorder/audio/目录。MediaStore.Audio.Media.INTERNAL_CONTENT_URI指向的是系统内部存储的私有媒体目录(比如系统自带的音乐目录),并不包含你自定义的/nexcox/...目录,所以切换到这个URI后查不到数据是正常的。
2. 路径匹配的逻辑问题
你的代码里用了AudioFilePath = "%" +"/nexcox/voicerecorder/audio/" +"%"这种通配符匹配,会导致匹配到所有路径中包含该字符串的文件——不管是内置存储还是外置SD卡的。另外,在Android 10(API 29)及以上,MediaStore.Audio.Media.DATA列已经被废弃,官方推荐用RELATIVE_PATH来匹配相对路径,避免绝对路径的适配问题。
3. 权限必须到位
- Android 9及以下:需要申请
READ_EXTERNAL_STORAGE权限,并且要动态申请(不能只在Manifest里加)。 - Android 10及以上:如果要访问非系统默认媒体目录(比如你自定义的
nexcox目录),除了READ_EXTERNAL_STORAGE,还需要申请MANAGE_EXTERNAL_STORAGE权限(注意这个权限需要用户手动在设置里开启,代码里可以引导用户跳转设置页面)。
4. 修正后的完整代码示例
下面是适配不同Android版本的查询代码,确保只读取内置存储中目标目录的音频文件:
// 先确保已经申请并获取了相应的存储权限 String targetRelativeDir = "nexcox/voicerecorder/audio/"; Uri audioUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; // 定义要查询的字段 String[] projection = { MediaStore.Audio.Media._ID, MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.RELATIVE_PATH }; String selection; String[] selectionArgs; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { // Android Q+ 用RELATIVE_PATH匹配相对路径 selection = MediaStore.Audio.Media.RELATIVE_PATH + " LIKE ?"; selectionArgs = new String[]{targetRelativeDir + "%"}; } else { // Android 9及以下 用绝对路径匹配 String internalRoot = Environment.getExternalStorageDirectory().getAbsolutePath(); String targetAbsolutePath = internalRoot + "/" + targetRelativeDir; selection = MediaStore.Audio.Media.DATA + " LIKE ?"; selectionArgs = new String[]{targetAbsolutePath + "%"}; } // 执行查询 Cursor cursor = getContentResolver().query( audioUri, projection, selection, selectionArgs, null ); if (cursor != null) { while (cursor.moveToNext()) { // 读取音频信息 String title = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE)); String filePath = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA)); Log.d("AudioQuery", "找到音频:" + title + ",路径:" + filePath); } cursor.close(); } else { Log.w("AudioQuery", "未查询到任何音频文件,请检查权限和路径是否正确"); }
另外还有个小细节:如果你的目标目录是刚创建的,或者里面的音频文件是刚添加的,系统可能还没完成MediaStore的索引,这时候可以发送Intent.ACTION_MEDIA_SCANNER_SCAN_FILE广播来触发扫描,确保文件能被查询到。
内容的提问来源于stack exchange,提问作者Khurram Shahzad
相关产品推荐
相关产品推荐

