
本文详解 CameraX VideoCapture 录制完成后如何安全、可靠地获取保存视频的 Uri,重点说明 VideoRecordEvent.Finalize 事件中通过 getOutputResults().getOutputUri() 提取 URI 的标准做法,并提供可直接复用的代码示例与关键注意事项。
本文详解 camerax `videocapture` 录制完成后如何安全、可靠地获取保存视频的 `uri`,重点说明 `videorecordevent.finalize` 事件中通过 `getoutputresults().getoutputuri()` 提取 uri 的标准做法,并提供可直接复用的代码示例与关键注意事项。
在使用 CameraX 的 VideoCapture 进行视频录制时,开发者常需在录制结束(即 VideoRecordEvent.Finalize 触发)后立即访问已保存视频的文件路径或内容 URI,用于后续播放、上传、缩略图生成等操作。但 CameraX 并未在 Recording 对象上暴露 getOutputUri() 方法,因此不能通过 recording 实例直接获取——正确路径必须从 VideoRecordEvent.Finalize 事件对象中提取。
✅ 正确获取方式:从 VideoRecordEvent.Finalize 中提取 URI
VideoRecordEvent.Finalize 是录制生命周期的最终确认事件,它封装了录制结果元数据,其中 getOutputResults() 返回一个 VideoRecordResult 对象,其 getOutputUri() 方法即为官方推荐的、线程安全且稳定可用的 URI 获取入口。
以下是优化后的完整示例代码(Kotlin/Java 兼容写法,此处以 Java 为主):
private void takeVideo() {
if (mso == null) return;
if (recording != null) {
recording.close();
recording = null;
return;
}
recording = videoCapture.getOutput()
.prepareRecording(this, mso)
.start(ContextCompat.getMainExecutor(this), new Consumer<VideoRecordEvent>() {
@Override
public void accept(VideoRecordEvent videoRecordEvent) {
if (videoRecordEvent instanceof VideoRecordEvent.Start) {
setBackgroundBtn(R.drawable.recoding);
Toast.makeText(CameraActivity.this, "Recording started...", Toast.LENGTH_SHORT).show();
} else if (videoRecordEvent instanceof VideoRecordEvent.Finalize) {
VideoRecordEvent.Finalize finalizeEvent = (VideoRecordEvent.Finalize) videoRecordEvent;
// ✅ 关键:从 Finalize 事件中安全获取保存 URI
Uri savedUri = finalizeEvent.getOutputResults().getOutputUri();
if (savedUri != null) {
Log.d("CameraX", "Video saved to: " + savedUri.toString());
Toast.makeText(CameraActivity.this,
"Video saved to: " + savedUri.toString(),
Toast.LENGTH_LONG).show();
// ✅ 后续操作建议(如播放、查询媒体库)
// MediaScannerConnection.scanFile(this, new String[]{savedUri.getPath()}, null, null);
} else {
Toast.makeText(CameraActivity.this,
"Failed to get output URI — check output options",
Toast.LENGTH_LONG).show();
}
setBackgroundBtn(R.drawable.round_bg);
Toast.makeText(CameraActivity.this, "Recording stopped.", Toast.LENGTH_SHORT).show();
}
}
});
}⚠️ 注意事项与最佳实践
- URI 可能为 null:当 MediaStoreOutputOptions 或 FileOutputOptions 配置异常(如权限缺失、目录不可写、存储空间不足),或 VideoRecordEvent.Finalize.getResultCode() 返回非 RESULT_SUCCESS 时,getOutputUri() 将返回 null。务必做空值校验。
- 仅在 Finalize 事件中读取:VideoRecordEvent.Start 和 VideoRecordEvent.Pause 等中间事件不包含输出结果,强行强转会抛 ClassCastException。
-
URI 类型取决于输出配置:
- 使用 MediaStoreOutputOptions → 返回 content:// URI(推荐,自动适配 Android 10+ 分区存储);
- 使用 FileOutputOptions → 返回 file:// URI(Android 7.0+ 需配置 FileProvider,且不兼容 Scoped Storage 强制场景)。
- 无需反射或私有字段访问:文中提到的 recording.mRecorder.mOutputUri.uriString 属于内部实现细节,极易因 CameraX 版本升级而失效,绝对禁止在生产代码中使用反射或访问包私有成员。
- 及时释放资源:recording.close() 应仅在明确终止录制流程时调用;正常录制结束由 CameraX 自动管理,开发者只需监听 Finalize 即可。
✅ 总结
CameraX 的设计哲学强调“事件驱动”与“结果导向”,视频 URI 不是录制过程的属性,而是录制结果的一部分。因此,唯一合规、健壮、可维护的获取方式,就是在 VideoRecordEvent.Finalize 回调中调用 event.getOutputResults().getOutputUri()。配合合理的错误处理与输出配置,即可无缝集成至任意视频处理工作流中。










