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

Jetpack Compose集成CameraX:相机预览退出功能实现遇阻

解决Jetpack Compose中CameraX退出预览冻结问题

问题原因

直接调用cameraController.unbind()时出现冻结,通常是因为相机操作的线程时机不正确,或者未遵循Compose组件生命周期管理相机资源。

解决方案

通过状态控制CameraContent的显示/隐藏,结合DisposableEffect自动管理相机的绑定与解绑,避免手动调用unbind()带来的线程冲突。

修改后的代码

  1. 主页面(Page类):
class Page : Screen {
    @SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
    @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
    @Composable
    override fun Content() {
        val scrollState = rememberScrollState()
        val navigator = LocalNavigator.currentOrThrow
        var showCameraPreview by remember { mutableStateOf(false) }
        val pictureList = mutableListOf<ImageBitmap>()

        Scaffold(
            topBar = { },
            bottomBar = { },
            content = {
                Column(
                    modifier = Modifier
                        .fillMaxSize()
                        .verticalScroll(scrollState)
                        .padding(it)
                ) {
                    // 页面原有内容

                    Button(onClick = { showCameraPreview = true }) {
                        Text(text = "打开相机")
                    }
                }
            }
        )
        if (showCameraPreview) {
            // 传递关闭回调,让父组件控制预览状态
            CameraContent(onClose = { showCameraPreview = false })
        }
    }
}
  1. CameraContent可组合项:
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun CameraContent(onClose: () -> Unit) {
    val context = LocalContext.current
    val lifecycleOwner = LocalLifecycleOwner.current
    val cameraController = remember { LifecycleCameraController(context) }

    // 用DisposableEffect自动管理相机生命周期
    DisposableEffect(lifecycleOwner, cameraController) {
        // 组件显示时绑定相机到生命周期
        cameraController.bindToLifecycle(lifecycleOwner)
        // 组件销毁时自动解绑相机
        onDispose {
            cameraController.unbind()
        }
    }

    Scaffold(
        modifier = Modifier.fillMaxSize(),
        floatingActionButton = { },
        floatingActionButtonPosition = FabPosition.Center,
    ) { paddingValues: PaddingValues ->
        Box {
            AndroidView(
                modifier = Modifier
                    .fillMaxSize()
                    .padding(paddingValues),
                factory = { context ->
                    PreviewView(context).apply {
                        layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
                        setBackgroundColor(Color.BLACK)
                        scaleType = PreviewView.ScaleType.FILL_START
                        controller = cameraController
                    }
                }
            )
            // 退出按钮,点击触发关闭回调
            Button(
                onClick = onClose,
                modifier = Modifier
                    .align(Alignment.TopEnd)
                    .padding(16.dp)
            ) {
                Icon(
                    imageVector = Icons.Default.Close,
                    contentDescription = "关闭相机",
                )
            }
        }
    }
}

关键说明

  • 状态提升:将相机预览的显示状态showCameraPreview放在父组件中管理,CameraContent通过回调触发状态变更,符合Compose的状态管理最佳实践。
  • DisposableEffect:确保相机在Compose组件显示时绑定生命周期,销毁时自动解绑,避免手动操作的线程问题,彻底解决冻结现象。
  • 线程安全:CameraX的绑定/解绑操作在DisposableEffect的回调中执行,遵循Compose的生命周期调度,保证操作在正确线程执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 04:20:11