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

CameraX 1.2.1结合Jetpack Compose相机预览异常求助

CameraX 1.2.1 与 Jetpack Compose 集成预览无显示问题修复

问题核心原因

  1. 布局层级遮挡:原代码中Icon组件先于AndroidView渲染,且设置了fillMaxWidth()和height(IntrinsicSize.Max),完全覆盖相机预览区域,仅在返回页面时Icon随页面销毁才短暂露出预览。
  2. 初始化时机错误:依赖硬编码的delay(2000)触发UI渲染,未关联权限申请结果,可能出现权限未通过就执行相机绑定的情况。
  3. 预览绑定逻辑不当:在LaunchedEffect中提前绑定预览,但此时AndroidView尚未加入Compose树,SurfaceProvider关联失效。

修复后的代码

@Composable
@Destination
fun TakePictureScreen(
    viewModel: TakePictureViewModel = hiltViewModel()
) {
    val lensFacing = CameraSelector.LENS_FACING_FRONT
    val context = LocalContext.current
    val lifecycleOwner = LocalLifecycleOwner.current

    val hasCameraPermission = remember { mutableStateOf(false) }
    val preview = remember { Preview.Builder().build() }
    val imageCapture = remember { ImageCapture.Builder().build() }
    val cameraSelector = remember {
        CameraSelector.Builder()
            .requireLensFacing(lensFacing)
            .build()
    }

    val cameraPermissionResultLauncher = rememberLauncherForActivityResult(
        contract = ActivityResultContracts.RequestPermission(),
        onResult = { isGranted ->
            hasCameraPermission.value = isGranted
            viewModel.onPermissionResult(
                permission = Manifest.permission.CAMERA,
                isGranted = isGranted
            )
        }
    )

    LaunchedEffect(Unit) {
        cameraPermissionResultLauncher.launch(Manifest.permission.CAMERA)
    }

    if (hasCameraPermission.value) {
        // 先渲染全屏预览
        AndroidView(
            factory = { ctx ->
                PreviewView(ctx).apply {
                    // View创建完成后关联SurfaceProvider并绑定相机
                    lifecycleScope.launch {
                        val cameraProvider = ProcessCameraProvider.getInstance(ctx).await()
                        cameraProvider.unbindAll()
                        preview.setSurfaceProvider(surfaceProvider)
                        cameraProvider.bindToLifecycle(
                            lifecycleOwner,
                            cameraSelector,
                            preview,
                            imageCapture
                        )
                    }
                }
            },
            modifier = Modifier.fillMaxSize()
        )

        // 后渲染局部Icon,避免遮挡预览
        Icon(
            tint = MaterialTheme.colors.primary,
            modifier = Modifier
                .align(Alignment.TopCenter)
                .padding(8.dp)
                .size(48.dp),
            painter = painterResource(R.drawable.can_location),
            contentDescription = stringResource(id = R.string.take_photo)
        )
    } else {
        Text(text = "需要相机权限才能使用")
    }
}

关键修改说明

  • 权限驱动UI:用hasCameraPermission替代硬编码延迟的cameraInit,确保权限通过后才渲染相机相关UI。
  • 调整布局顺序:将AndroidView放在Icon之前,且给Icon设置固定尺寸,避免覆盖全屏预览。
  • 正确绑定时机:将相机绑定逻辑移至AndroidView的factory回调中,确保PreviewView已完成创建后再关联SurfaceProvider和相机生命周期。
  • 规范相机提供者获取:使用ProcessCameraProvider.getInstance(ctx).await()异步获取相机提供者,避免阻塞主线程。

问题截图说明

  • 相机功能触发前界面
    相机触发前
  • 相机运行中界面(右上角绿色标识显示相机已启动)
    相机运行中
  • 返回过渡时短暂显示的相机画面
    返回过渡画面

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 05:47:53