【发布时间】:2023-02-19 02:29:05
【问题描述】:
我有一个 bottomSheetScaffold,其中包含一个 BottomSheet
BottomSheet 使用设备的摄像头,我将 CameraX 与 Google 的 MLkit 一起用于条形扫描
让我们考虑接受许可 发生了什么(不正确):一旦我向上展开底页,我就会显示 CameraPreview、显示相机预览和分析预览图像的 ImageAnalyzer。
现在 bottomSheet 已展开,相机预览可见并按预期工作
然后我折叠 bottomSheet,但相机仍在工作(分析仪也是如此,
imageAnalysis.clearAnalyzer()清除分析部分)
结果:不是我想要的正确行为
那么如何在 bottomSheetState 折叠后停止相机工作和使用资源,并且仅在 bottomSheetState 展开时才允许相机
它是如何工作的(错误):
我遇到的问题是,相机绑定到活动的生命周期,而不是可组合本身,当重新组合发生时,它仍然认为相机是活动的,因为它没有附加到组合生命周期
Composition 是如何工作的:
代码:
@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 的相机作为视图,这并不能解决问题
【问题讨论】:
标签: android kotlin android-jetpack-compose android-camera bottom-sheet