权限获批后跳转相机Fragment仅显示黑屏的问题求助
看起来你遇到的问题确实挺棘手的——权限申请通过后跳转相机Fragment却只看到黑屏,而且试了几种方法都没解决对吧?我先帮你梳理下核心问题,再给你几个可行的调整方向。
问题根源分析
从你的代码来看,当前的onRequestPermissionsResult存在一个关键顺序问题:你先执行了navigateToCamera()跳转逻辑,之后才把权限结果分发给NavHost里的子Fragment。这就导致相机Fragment在跳转完成、初始化相机的时候,还没收到权限获批的通知,自然无法正常启动相机,最终显示黑屏。
针对性解决方案
1. 调整权限结果的分发顺序(最直接的修复)
把「向子Fragment分发权限结果」的逻辑,移到处理相机权限跳转的前面。这样相机Fragment在跳转前就已经收到权限获批的回调,初始化相机时就能正常获取权限了。
修改后的MainActivity.kt的onRequestPermissionsResult代码:
@SuppressLint("MissingSuperCall") override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<String>, grantResults: IntArray ) { // 第一步:先把权限结果分发给NavHost中的所有子Fragment val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host) as? NavHostFragment navHostFragment?.childFragmentManager?.fragments?.forEach { frag -> frag.onRequestPermissionsResult(requestCode, permissions, grantResults) } // 第二步:处理自身的权限逻辑 if (requestCode == REQUEST_CODE_MAIN_ACTIVITY) { if (grantResults[0] == PackageManager.PERMISSION_DENIED) { alertDialog = localizationProvider.showManualLocationPickerDialog( this, REQUEST_CODE_MAIN_ACTIVITY ) return } } if (requestCode == cameraPermissionProvider.requestCode) { if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { navigateToCamera() } else { showCameraDialogPermission() } } // 可选:如果NavHost的分发逻辑已经覆盖子Fragment,super调用可以保持注释,否则打开 // super.onRequestPermissionsResult(requestCode, permissions, grantResults) }
2. 确保相机Fragment的初始化时机正确
在相机Fragment内部,不要在onViewCreated或onCreate中直接初始化相机,而是在确认权限已经获批后再启动相机。比如重写Fragment的onRequestPermissionsResult:
class CameraFragment : Fragment() { private val CAMERA_PERMISSION_REQUEST_CODE = 1001 override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<out String>, grantResults: IntArray ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == CAMERA_PERMISSION_REQUEST_CODE) { if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 权限通过后再初始化相机 startCamera() } else { // 权限拒绝的提示逻辑 Toast.makeText(requireContext(), "需要相机权限才能使用", Toast.LENGTH_SHORT).show() } } } private fun startCamera() { // 这里写你的相机初始化逻辑(比如CameraX/Camera2的启动代码) } }
3. 改用Activity Result API优化权限申请流程(更符合Jetpack最佳实践)
你提到用新的权限启动器时,navController是lazy导致跳转失败。其实可以把权限申请逻辑移到需要跳转的Fragment内部,而不是在Activity中处理,这样能避免跨组件的权限结果传递问题:
// 在需要跳转相机的Fragment中实现 private val requestCameraPermission = registerForActivityResult( ActivityResultContracts.RequestPermission() ) { isGranted -> if (isGranted) { // 权限通过后直接跳转,用当前Fragment的navController更可靠 findNavController().navigate(R.id.action_to_camera_fragment) } else { showCameraPermissionDialog() } } // 触发权限申请的方法 private fun prepareToOpenCamera() { when { ContextCompat.checkSelfPermission( requireContext(), Manifest.permission.CAMERA ) == PackageManager.PERMISSION_GRANTED -> { findNavController().navigate(R.id.action_to_camera_fragment) } shouldShowRequestPermissionRationale(Manifest.permission.CAMERA) -> { // 显示权限必要性说明弹窗 showPermissionRationaleDialog() } else -> { requestCameraPermission.launch(Manifest.permission.CAMERA) } } }
总结
核心问题就是权限结果的分发晚于跳转动作,导致相机Fragment初始化时没有权限可用。调整分发顺序、确保Fragment在权限获批后再初始化相机,这两个点应该就能解决黑屏问题。如果后续想优化架构,把权限申请移到Fragment内部用Activity Result API处理,会更稳定也更符合现代Android开发的规范。
内容来源于stack exchange




