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

Android跨Fragment传递并显示CameraX拍摄图片的方法

Android 跨Fragment传递并显示CameraX拍摄图片实现方案

方案选型说明

  • 绝对不要传递Bitmap:Bitmap属于大内存对象,通过Bundle跨组件传递很容易触发TransactionTooLargeException崩溃,还会平白占用多倍不必要的内存,属于吃力不讨好的方案。
  • 最优方案是直接传递Uri:Uri本身实现了Parcelable接口,天然支持Navigation的Bundle、Safe Args传递,你之前遇到传值为null的问题完全是代码逻辑错误导致的,不是方案本身不可行。

原有代码问题排查

  1. 传参逻辑错误:你没有直接传递output.savedUri这个Uri对象,反而取了Uri的path字段转成字符串传递。Android 10+开启分区存储后,MediaStore返回的都是content://类型的Uri,靠截取的文件路径根本无法正常访问文件,从根源上会导致加载失败。
  2. 取参逻辑错误:你传参时是直接把值存在Bundle的对应key下,取值时却先调用arguments?.getBundle("image")试图获取一个子Bundle,类型完全不匹配,拿到的结果自然是null。

修正后可运行代码

1. 修改CameraFragment的拍照回调传参逻辑

把原来onImageSaved方法里的传参部分替换为以下代码:

override fun onImageSaved(output: ImageCapture.OutputFileResults) {
    val savedUri = output.savedUri ?: return
    val msg = "Photo capture succeeded: $savedUri"
    Toast.makeText(requireContext(), msg, Toast.LENGTH_SHORT).show()
    Timber.d(msg)

    // 直接把Uri作为Parcelable存入Bundle,不要转path字符串
    val bundle = bundleOf("captured_image_uri" to savedUri)
    Navigation.findNavController(requireView()).navigate(
        R.id.cameraFragmentToCameraFinalFragment, 
        bundle
    )
}

如果你用Navigation Safe Args,直接在导航图的argument配置里把参数类型设为android.net.Uri,传参时直接传入Uri即可,不需要手动构造Bundle。

2. 修改PhotoFinalFragment的参数读取与图片加载逻辑

把原来onCreateView里的参数读取、图片加载部分替换为以下代码:

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    _binding = FragmentPhotoFinalBinding.inflate(inflater, container, false)

    // 直接从arguments根节点取Parcelable类型的Uri,不需要取子Bundle
    val imageUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        arguments?.getParcelable("captured_image_uri", Uri::class.java)
    } else {
        @Suppress("DEPRECATION")
        arguments?.getParcelable("captured_image_uri")
    }
    
    imageUri?.let { uri ->
        // 注意:原生setImageURI会在主线程解码图片,大图容易卡顿ANR,建议替换为Glide/Coil等图片加载库
        // Coil加载示例:binding.imageView.load(uri)
        // Glide加载示例:Glide.with(this).load(uri).into(binding.imageView)
        binding.imageView.setImageURI(uri)
    }

    binding.btnYes.setOnClickListener {
        Navigation.findNavController(requireView()).navigate(R.id.cameraFinalFragmentToStoryFragment)
    }

    binding.btnNo.setOnClickListener {
        Navigation.findNavController(requireView()).navigate(R.id.cameraFinalFragmentTocameraFragment)
    }
    return binding.root
}

额外注意事项

  • 不要直接拿content://类型Uri的path字段当本地文件路径使用,这个写法在开启分区存储的设备上完全没有权限读取对应文件,必须通过ContentResolver获取文件描述符访问,或者直接把Uri交给图片加载库处理。
  • 大尺寸拍摄图不建议直接用ImageView.setImageURI()加载,这个方法会在主线程执行图片解码,很容易造成界面卡顿甚至ANR,成熟的图片加载库会自动处理异步解码、内存缓存、尺寸压缩,体验稳定很多。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 13:33:23