You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

权限获批后跳转相机Fragment仅显示黑屏的问题求助

权限获批后跳转相机Fragment仅显示黑屏的问题求助

看起来你遇到的问题确实挺棘手的——权限申请通过后跳转相机Fragment却只看到黑屏,而且试了几种方法都没解决对吧?我先帮你梳理下核心问题,再给你几个可行的调整方向。

问题根源分析

从你的代码来看,当前的onRequestPermissionsResult存在一个关键顺序问题:你先执行了navigateToCamera()跳转逻辑,之后才把权限结果分发给NavHost里的子Fragment。这就导致相机Fragment在跳转完成、初始化相机的时候,还没收到权限获批的通知,自然无法正常启动相机,最终显示黑屏。

针对性解决方案

1. 调整权限结果的分发顺序(最直接的修复)

把「向子Fragment分发权限结果」的逻辑,移到处理相机权限跳转的前面。这样相机Fragment在跳转前就已经收到权限获批的回调,初始化相机时就能正常获取权限了。

修改后的MainActivity.ktonRequestPermissionsResult代码:

@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内部,不要在onViewCreatedonCreate中直接初始化相机,而是在确认权限已经获批后再启动相机。比如重写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

火山引擎 最新活动