使用MediaStore API保存音频时insert方法崩溃或返回null怎么解决?
问题原因与修复方案
1. 最初崩溃的原因
最开始仅传入DISPLAY_NAME就调用insert方法触发崩溃,是因为Android 10(API 29)及以上版本的MediaProvider处理公共媒体写入请求时,缺少必填参数导致底层解析文件属性时触发空指针,低版本系统虽然校验宽松,但也建议补全必要参数避免适配问题。
2. 新增代码后insert返回null的原因
你新增的代码存在三个核心问题:
- 路径拼接错误:
${directory}${song?.title}未添加路径分隔符,生成的路径格式非法,例如目录路径和文件名直接拼接为/storage/emulated/0/Android/data/包名/files/Music我的歌曲.mp3,非法路径会直接导致insert请求被系统拒绝 - 字段使用错误:
MediaStore.Audio.AudioColumns.DATA在Android 10及以上版本已被标记为只读,手动赋值会被系统忽略,部分定制ROM甚至会直接驳回写入请求 - 权限缺失:未申请对应存储权限,Android 12及以下需要
WRITE_EXTERNAL_STORAGE权限,Android 13及以上需要READ_MEDIA_AUDIO权限,权限不足会直接返回null
3. 完整修复方案
3.1 声明并申请存储权限
首先在AndroidManifest.xml中添加对应权限:
<!-- Android 12及以下适用 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <!-- Android 13及以上适用 --> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
运行时先动态申请对应权限,拿到权限授权后再执行写入逻辑。
3.2 正确构造ContentValues参数
适配不同Android版本的写入规则,参考代码如下:
ContentValues values = new ContentValues(); values.put(MediaStore.Audio.Media.DISPLAY_NAME, "My Song.mp3"); values.put(MediaStore.Audio.Media.TITLE, "My Song"); values.put(MediaStore.Audio.Media.MIME_TYPE, "audio/mpeg"); // Android 10及以上版本使用RELATIVE_PATH指定存储目录,不需要手动拼接路径 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { values.put(MediaStore.Audio.Media.RELATIVE_PATH, Environment.DIRECTORY_MUSIC); values.put(MediaStore.Audio.Media.IS_PENDING, 1); // 标记为待写入状态,避免写入过程中被其他应用扫描 } else { // 低版本手动拼接合法路径 File musicDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC); File audioFile = new File(musicDir, "My Song.mp3"); values.put(MediaStore.Audio.Media.DATA, audioFile.getAbsolutePath()); } ContentResolver resolver = getContentResolver(); Uri audioUri = resolver.insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, values); if (audioUri != null) { // 拿到URI后打开输出流写入音频数据 try (OutputStream os = resolver.openOutputStream(audioUri)) { // 此处写入你的音频二进制数据 // ...... // 写入完成后更新待写入状态(仅Android 10+需要) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { values.clear(); values.put(MediaStore.Audio.Media.IS_PENDING, 0); resolver.update(audioUri, values, null, null); } } catch (IOException e) { e.printStackTrace(); } }
3.3 额外注意事项
如果你仅需要将音频保存在应用专属目录下,不需要被其他音频应用扫描到,不需要使用MediaStore,直接用File API读写即可,只有需要将文件共享到系统媒体库时才需要调用MediaStore接口。
内容的提问来源于stack exchange,提问作者S4D3V
相关产品推荐
相关产品推荐

