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

如何在BottomSheet折叠时停止CameraX相机运行?

解决BottomSheet折叠时CameraX相机资源未释放的问题

核心问题在于CameraX默认绑定Activity生命周期,而BottomSheet的展开/折叠属于Composable组合生命周期范畴,两者不匹配导致折叠后相机仍在后台运行。以下是具体解决思路和实现代码:

关键思路

用DisposableEffect监听BottomSheet的状态变化,将相机的绑定/解绑逻辑与BottomSheet的展开状态强关联,替代原有的Activity生命周期绑定:

  • 当BottomSheet展开时,初始化并绑定CameraX的Preview和ImageAnalysis UseCase
  • 当BottomSheet折叠时,解绑所有UseCase并清空引用,彻底释放相机资源
  • 利用DisposableEffect的onDispose回调处理Composable退出组合时的资源清理

实现代码

@Composable
fun BarcodeScannerBottomSheet() {
    val bottomSheetState = rememberBottomSheetState(BottomSheetValue.Collapsed)
    val context = LocalContext.current
    val lifecycleOwner = LocalLifecycleOwner.current
    
    // 持有CameraProvider及UseCase实例
    var cameraProvider: ProcessCameraProvider? by remember { mutableStateOf(null) }
    var previewUseCase: Preview? by remember { mutableStateOf(null) }
    var imageAnalysisUseCase: ImageAnalysis? by remember { mutableStateOf(null) }
    
    // 初始化CameraProvider
    LaunchedEffect(Unit) {
        cameraProvider = ProcessCameraProvider.getInstance(context).await()
    }
    
    // 绑定BottomSheet状态与相机生命周期
    DisposableEffect(bottomSheetState.currentValue, cameraProvider) {
        val provider = cameraProvider ?: return@DisposableEffect onDispose {}
        
        if (bottomSheetState.currentValue == BottomSheetValue.Expanded) {
            // 配置预览组件(替换成你的SurfaceView引用)
            previewUseCase = Preview.Builder().build().also {
                it.setSurfaceProvider(yourSurfaceView.surfaceProvider)
            }
            
            // 配置条码分析器
            imageAnalysisUseCase = ImageAnalysis.Builder()
                .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                .build().also {
                    it.setAnalyzer(Executors.newSingleThreadExecutor(), yourBarcodeAnalyzer)
                }
            
            // 绑定相机到当前LifecycleOwner(贴近Composable组合生命周期)
            try {
                provider.unbindAll()
                provider.bindToLifecycle(
                    lifecycleOwner,
                    CameraSelector.DEFAULT_BACK_CAMERA,
                    previewUseCase,
                    imageAnalysisUseCase
                )
            } catch (e: Exception) {
                Log.e("CameraX", "相机绑定失败", e)
            }
        } else {
            // 折叠时解绑所有UseCase,释放资源
            provider.unbindAll()
            previewUseCase = null
            imageAnalysisUseCase = null
        }
        
        // Composable退出组合时彻底清理
        onDispose {
            provider.unbindAll()
            cameraProvider = null
        }
    }
    
    // 你的BottomSheetScaffold实现
    BottomSheetScaffold(
        sheetState = bottomSheetState,
        sheetContent = {
            // 相机预览布局(包含你的SurfaceView)
            AndroidView(
                factory = { ctx -> SurfaceView(ctx).apply { id = R.id.camera_preview } },
                update = { view -> yourSurfaceView = view }
            )
        }
    ) {
        // 主内容区
    }
}

注意事项

  1. 必须调用cameraProvider.unbindAll()才能彻底停止相机,仅调用imageAnalysis.clearAnalyzer()只会移除分析器,相机实例仍会保持活跃
  2. 绑定相机时使用LocalLifecycleOwner.current而非Activity的LifecycleOwner,让相机生命周期更贴近Composable的组合生命周期
  3. 所有CameraX相关实例需用remember持有,避免重组时重复初始化

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 01:15:51