安卓10中MediaRecorder的setOutputFile如何适配分区存储Uri
安卓分区存储场景下 MediaRecorder 录音输出适配
核心适配思路
安卓10+上线分区存储机制后,不推荐通过非正规手段将公开可访问的Uri解析为真实文件路径——这类实现不仅兼容性差,在安卓11及以上版本会直接触发权限拦截。MediaRecorder本身原生支持通过FileDescriptor作为输出目标,完全可以跳过「获取物理文件路径」的环节,直接基于拿到的可写Uri完成录音输出。
原代码中需要删除的两行逻辑:
recordingName = getFilename(); recorder.setOutputFile(recordingName);
替换为基于Uri的FileDescriptor输出逻辑即可,其他录音配置(音频源、输出格式、编码器、监听回调)的代码完全不需要改动。
调整后的核心实现
public void startRecording() { recorder = new MediaRecorder(); recorder.setAudioSource(MediaRecorder.AudioSource.MIC); recorder.setOutputFormat(output_formats[currentFormat]); recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); // 提前通过MediaStore API/用户授权拿到可写的录音输出Uri Uri outputUri = createAudioOutputUri(); ParcelFileDescriptor pfd = null; try { // 通过Uri打开可写的文件描述符 pfd = getContentResolver().openFileDescriptor(outputUri, "w"); // 直接将文件描述符传给MediaRecorder,无需传入物理文件路径 recorder.setOutputFile(pfd.getFileDescriptor()); recorder.setOnErrorListener(errorListener); recorder.setOnInfoListener(infoListener); recorder.prepare(); recorder.start(); handler.post(updateVisualizer); } catch (IllegalStateException | IOException e) { e.printStackTrace(); } }
其中创建录音输出Uri的适配方法,不需要申请额外存储权限:
private Uri createAudioOutputUri() { ContentValues recordInfo = new ContentValues(); String fileName = "录音_" + System.currentTimeMillis() + ".amr"; recordInfo.put(MediaStore.Audio.Media.DISPLAY_NAME, fileName); recordInfo.put(MediaStore.Audio.Media.MIME_TYPE, "audio/amr"); // 安卓Q及以上指定录音存储的公共相对路径 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { recordInfo.put(MediaStore.Audio.Media.RELATIVE_PATH, "Music/应用录音目录/"); } // 向媒体库插入条目拿到可直接写入的Uri return getContentResolver().insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, recordInfo); }
关键注意点
- 全程不需要调用各类第三方工具类把Uri转成本地物理路径,这类方案在高版本安卓上的兼容性没有保障,完全违背分区存储的设计原则
- 打开文件描述符时要传入正确的访问权限,新建空录音文件用
"w"权限即可,需要追加写入的场景用"rw"权限 - ParcelFileDescriptor的关闭时机要对齐录音流程:必须在录音停止、
MediaRecorder.release()完成之后再释放,避免提前关闭导致录音内容写入失败、文件损坏
内容的提问来源于stack exchange,提问作者user3661581
相关产品推荐
相关产品推荐

