You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android 4.3 Jelly Bean(API 18)Content URI引发相机录制崩溃求助

解决Android 4.3 Jelly Bean(API18)相机录视频时data.getData()空指针问题

这个问题在Android 4.3这类旧版本系统里非常常见——系统自带的相机应用在你指定录制视频的输出目标后,并不会通过onActivityResult的data参数返回视频的URI,直接调用data.getData()自然就会触发NullPointerException,导致应用崩溃。

下面是最可靠的解决方案,核心思路是提前指定视频的保存路径,不用依赖返回的data参数:

步骤1:创建用于保存视频的临时文件

先写一个方法来生成唯一的视频文件,避免文件名冲突:

private File createVideoFile() throws IOException {
    // 用时间戳生成唯一文件名
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
    String videoFileName = "RECORD_" + timeStamp + "_";
    // 存在应用私有电影目录,API19+无需额外权限,API18仍需WRITE_EXTERNAL_STORAGE
    File storageDir = getExternalFilesDir(Environment.DIRECTORY_MOVIES);
    return File.createTempFile(videoFileName, ".mp4", storageDir);
}

步骤2:启动相机时指定输出路径

启动相机Intent的时候,通过MediaStore.EXTRA_OUTPUT把刚才创建的文件对应的URI传进去,告诉相机直接把视频写到这个文件里:

private static final int VIDEO_CAPTURE_REQUEST = 1;
private Uri mSavedVideoUri; // 保存提前创建的视频URI

private void launchCameraForVideo() {
    Intent videoCaptureIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
    // 先检查设备是否有相机应用
    if (videoCaptureIntent.resolveActivity(getPackageManager()) != null) {
        File videoFile = null;
        try {
            videoFile = createVideoFile();
        } catch (IOException e) {
            // 处理文件创建失败的情况,比如弹出提示
            Toast.makeText(this, "无法创建视频文件", Toast.LENGTH_SHORT).show();
            e.printStackTrace();
            return;
        }
        
        if (videoFile != null) {
            mSavedVideoUri = Uri.fromFile(videoFile);
            videoCaptureIntent.putExtra(MediaStore.EXTRA_OUTPUT, mSavedVideoUri);
            // 可以额外设置视频质量、时长等参数
            videoCaptureIntent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 30); // 最长30秒
            startActivityForResult(videoCaptureIntent, VIDEO_CAPTURE_REQUEST);
        }
    } else {
        Toast.makeText(this, "未找到相机应用", Toast.LENGTH_SHORT).show();
    }
}

步骤3:修改onActivityResult逻辑

不再从data里取URI,直接用我们提前保存的mSavedVideoUri:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    
    if (requestCode == VIDEO_CAPTURE_REQUEST) {
        if (resultCode == RESULT_OK) {
            // 录制成功,直接使用mSavedVideoUri处理视频
            if (mSavedVideoUri != null) {
                // 示例:打印视频路径
                Log.d("VideoRecord", "视频已保存至:" + mSavedVideoUri.getPath());
                // 这里可以添加播放、上传等逻辑
            }
        } else if (resultCode == RESULT_CANCELED) {
            // 用户取消录制,清理临时文件
            if (mSavedVideoUri != null) {
                File tempVideo = new File(mSavedVideoUri.getPath());
                if (tempVideo.exists()) {
                    tempVideo.delete();
                }
            }
            Toast.makeText(this, "录制已取消", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "录制失败", Toast.LENGTH_SHORT).show();
        }
    }
}

必要的权限配置

在AndroidManifest.xml里添加相机和存储权限(适配API18):

<!-- 相机权限(可选,若应用必须依赖相机则设为required="true") -->
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />

<!-- API18及以下需要外部存储写入权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

为什么这个方案有效?

Android 4.3及更早的系统中,相机应用的设计逻辑是:当你通过EXTRA_OUTPUT指定了输出目标后,相机不会将视频URI封装到返回的Intent data中,而是直接将视频文件写入你指定的路径。所以我们完全不需要依赖data参数,直接使用提前创建的URI即可避免空指针问题。

内容的提问来源于stack exchange,提问作者andios

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:04:03