我有一个bottomSheetScaffold,其中包含一个BottomSheet
BottomSheet使用设备的Camera,我使用CameraX和Google的MLkit进行条形扫描
让我们考虑许可被接受会发生什么(不正确):一旦我向上展开底部表单,我将显示CameraPreview、show camera preview和分析预览图像的ImageAnalyzer。
现在bottomSheet已展开,相机预览可见并按预期工作,然后我折叠bottomSheet,但相机仍在工作(分析器也是如此,imageAnalysis.clearAnalyzer()
清除分析部分)
结果:这不是我本意
如何在bottomSheetState折叠后停止camera工作和使用资源,并仅在bottomSheetState展开时允许camera
工作原理(错误):
我遇到的问题是,摄像头绑定到活动的生命周期,而不是组合本身,当重新组合发生时,它仍然认为摄像头是活动的,因为它没有附加到组合生命周期
合成的工作原理:
编码:
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun BottomSheetContent(
modifier: Modifier = Modifier,
bottomSheetState: BottomSheetState
) {
Column(
modifier = modifier
.fillMaxWidth()
.fillMaxHeight(0.8f)
) {
PeekBar()
ScanningSerialTextTitle(modifier)
if (bottomSheetState.isExpanded) {
CameraBox(modifier)
} else {
EmptyBox()
}
}
}
@Composable
fun EmptyBox(modifier: Modifier = Modifier) {
Box(
modifier = modifier
.fillMaxSize()
.background(color = Color.DarkGray)
)
}
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun CameraBox(modifier: Modifier = Modifier) {
val cameraPermissionState = rememberPermissionState(permission = Manifest.permission.CAMERA)
val lifeCycleOwner = LocalLifecycleOwner.current
DisposableEffect(key1 = lifeCycleOwner, effect = {
val observer = LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_START) {
cameraPermissionState.launchPermissionRequest()
}
}
lifeCycleOwner.lifecycle.addObserver(observer)
onDispose { lifeCycleOwner.lifecycle.removeObserver(observer) }
})
cameraPermissionState.handlePermissionCases(
ShouldShowRationaleContent = {
ShouldShowRationaleContent(cameraPermissionState = cameraPermissionState)
},
PermissionDeniedPermanentlyContent = {
PermissionDeniedPermanentContent()
}) {
val context = LocalContext.current
val barCodeVal = remember { mutableStateOf("") }
CameraPreview(onBarcodeDetected = { barcodes ->
barcodes.forEach { barcode ->
barcode.rawValue?.let { barcodeValue ->
barCodeVal.value = barcodeValue
Toast.makeText(context, barcodeValue, Toast.LENGTH_SHORT).show()
}
}
}, onBarcodeFailed = {}, onBarcodeNotFound = {})
}
}
@Composable
fun CameraPreview(
modifier: Modifier = Modifier,
onBarcodeDetected: (barcodes: List<Barcode>) -> Unit,
onBarcodeFailed: (exception: Exception) -> Unit,
onBarcodeNotFound: (text: String) -> Unit,
) {
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
AndroidView(
modifier = modifier.fillMaxSize(),
factory = { androidViewContext -> initPreviewView(androidViewContext) },
update = { previewView: PreviewView ->
val cameraSelector: CameraSelector = buildCameraSelector(CameraSelector.LENS_FACING_BACK)
val cameraExecutor: ExecutorService = Executors.newSingleThreadExecutor()
val cameraProviderFuture: ListenableFuture<ProcessCameraProvider> =
ProcessCameraProvider.getInstance(context)
val preview = buildPreview().also {
it.setSurfaceProvider(previewView.surfaceProvider)
}
val barcodeAnalyser = BarCodeAnalyser(
onBarcodeDetected = onBarcodeDetected,
onBarcodeFailed = onBarcodeFailed,
onBarCodeNotFound = onBarcodeNotFound
)
val imageAnalysis: ImageAnalysis =
buildImageAnalysis(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST).also {
it.setAnalyzer(cameraExecutor, barcodeAnalyser)
}
cameraProviderFuture.addListener({
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
try {
cameraProvider.unbindAll() //Make sure we only use 1 usecase related to camera
val camera = cameraProvider.bindToLifecycle(
lifecycleOwner,
cameraSelector,
preview,
imageAnalysis
)
camera.cameraControl.enableTorch(true)
} catch (e: Exception) {
Log.d("TAG", "CameraPreview: ${e.localizedMessage}")
}
}, ContextCompat.getMainExecutor(context))
}
)
}
private fun initPreviewView(androidViewContext: Context): PreviewView {
val previewView = PreviewView(androidViewContext).apply {
implementationMode = PreviewView.ImplementationMode.COMPATIBLE
}
return previewView
}
private fun buildPreview(): Preview {
return Preview.Builder().build()
}
private fun buildImageAnalysis(imageAnalysisStrategy: Int): ImageAnalysis {
return ImageAnalysis.Builder()
.setBackpressureStrategy(imageAnalysisStrategy)
.build()
}
private fun buildCameraSelector(cameraLens: Int): CameraSelector {
return CameraSelector.Builder()
.requireLensFacing(cameraLens)
.build()
}
我尝试过:我尝试将BottomSheetState的状态传递给可组合对象,并检查状态,这应该会触发重新组合,但由于我使用Android的Camera作为View,因此这并不能解决问题
2条答案
按热度按时间b1uwtaje1#
首先您将为摄像机状态创建一个变量
**然后,**您将检测到上下拖动底部纸张的时间
//现在底层工作表被隐藏showcamera=false
最后您将检查showcamrea = true是否为真,然后请求此摄像头或类似视图
希望对你有帮助!
kuarbcqp2#
我找到了一个解决方案,当composable从composition中删除时,我使用
DisposableEffect
关闭摄像头首先,在代码中的
CameraPreview
组合函数上,定义一个ProcessCameraProvider
类型的变量,并将其赋值为空值然后,您将定义一个
DisposableEffect
,其密钥为cameraProvider
,当组合解组合时,您将关闭摄像头替换旧代码行
全新的
cameraProvider
然后在
try-catch
块中,由于我们使用的是空值,当需要检查它是否为空时,我们将使用let