ActivityResultLauncher<Intent>返回Activity前提前返回结果码问题
问题现象
- 从当前Activity拉起第三方OpenCamera应用,相机可以正常启动,但启动后立刻返回结果码,未定位到根因
- 日志打印返回的结果码值为
0,即Activity.RESULT_CANCELED - 疑问:若目标相机仅完成拍照操作、不返回任何数据,是否需要调整现有实现逻辑
- 原有实现代码:
private void cameraOpen() { Intent cam = getContext().getPackageManager().getLaunchIntentForPackage("net.sourceforge.opencamera"); postCamera.launch(cam); } ActivityResultLauncher<Intent> postCamera = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { if (result.getResultCode() == Activity.RESULT_OK) { Log.i("SAKEGA", "WAK"); dispatchTakePictureIntent(); } else { Log.i("SAKEGA", String.valueOf(result.getResultCode())); } });
问题根因
返回0和相机是否返回数据无关,核心是拉起逻辑写错了:getLaunchIntentForPackage获取的是应用的桌面入口Intent,和用户手动点桌面图标启动应用的行为完全一致,这种启动方式没有携带任何拍照请求的参数,OpenCamera识别到这不是外部发起的拍照调用,不会停留在拍照页面等待用户操作,会直接走普通启动流程后返回取消结果。
修复方案
- 不要用普通桌面启动Intent发起拍照请求,必须使用Android标准的拍照Action
MediaStore.ACTION_IMAGE_CAPTURE构造Intent,如果需要固定拉起OpenCamera,单独给Intent设置包名即可。 - 不要等相机返回Intent里携带的图片数据,几乎所有第三方相机都不会直接在返回结果中放Bitmap(很容易触发跨进程传输数据过大的崩溃),正确做法是提前创建好图片存储文件,生成FileProvider Uri后通过
MediaStore.EXTRA_OUTPUT参数传给相机,相机会直接把拍摄的图片写入你指定的路径。 - 给Intent添加
FLAG_GRANT_WRITE_URI_PERMISSION权限,保证相机有权限写入你指定的文件路径。 - 修正后的代码参考:
// 全局存储拍照输出路径的Uri private Uri photoOutputUri; private void cameraOpen() { Intent cam = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // 指定拉起OpenCamera,去掉该行则会弹出应用选择器让用户选可用相机 cam.setPackage("net.sourceforge.opencamera"); // 提前创建拍照存储文件 File photoFile = new File( getExternalFilesDir(Environment.DIRECTORY_PICTURES), "camera_shot_" + System.currentTimeMillis() + ".jpg" ); // 生成对应FileProvider的访问Uri,注意替换成你自己的FileProvider配置的authority photoOutputUri = FileProvider.getUriForFile( getContext(), getContext().getPackageName() + ".fileprovider", photoFile ); // 给相机授予临时写入权限 cam.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); // 传入输出路径 cam.putExtra(MediaStore.EXTRA_OUTPUT, photoOutputUri); // 提前判断是否有可处理该意图的相机应用,避免ActivityNotFound崩溃 if (cam.resolveActivity(getContext().getPackageManager()) != null) { postCamera.launch(cam); } } ActivityResultLauncher<Intent> postCamera = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { if (result.getResultCode() == Activity.RESULT_OK) { Log.i("SAKEGA", "拍照成功,图片已写入photoOutputUri对应路径"); // 直接使用全局的photoOutputUri做后续图片处理即可,不需要从result中取数据 dispatchTakePictureIntent(); } else { Log.i("SAKEGA", "拍照失败/用户取消,结果码:" + result.getResultCode()); } } );
注意事项
- 上述实现需要你提前在AndroidManifest.xml中配置FileProvider,否则生成Uri时会抛出异常。
- 按照Android相机Intent的标准规范,配置了
EXTRA_OUTPUT参数后,相机返回的Intent通常是空值,这是正常设计,不是相机实现错误。
内容的提问来源于stack exchange,提问作者shiho
相关产品推荐
相关产品推荐

