From 0d64009f1928b1f5b6971782ffdf259f2c2701ac Mon Sep 17 00:00:00 2001 From: agra Date: Wed, 13 May 2026 10:05:59 +0300 Subject: [PATCH] scanner: unbind CameraX on PlatformView dispose (Android) dispose() only shut down the analysis executor, leaving the camera bound to the activity LifecycleOwner so the indicator stayed on after the scan page popped. Hold the ProcessCameraProvider, unbindAll() in dispose, and guard the async bind callback so we don't rebind after dispose. --- .../src/main/kotlin/io/swipelab/ux/ScannerPlugin.kt | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/android/src/main/kotlin/io/swipelab/ux/ScannerPlugin.kt b/android/src/main/kotlin/io/swipelab/ux/ScannerPlugin.kt index 94bcd5b..9c43060 100644 --- a/android/src/main/kotlin/io/swipelab/ux/ScannerPlugin.kt +++ b/android/src/main/kotlin/io/swipelab/ux/ScannerPlugin.kt @@ -171,6 +171,8 @@ private class ScannerPlatformView( ), ) } + private var cameraProvider: ProcessCameraProvider? = null + private var disposed = false init { if (lifecycleOwner != null) bindCamera(context, lifecycleOwner) @@ -179,7 +181,9 @@ private class ScannerPlatformView( private fun bindCamera(context: Context, lifecycleOwner: LifecycleOwner) { val cameraProviderFuture = ProcessCameraProvider.getInstance(context) cameraProviderFuture.addListener({ - val cameraProvider = cameraProviderFuture.get() + if (disposed) return@addListener + val provider = cameraProviderFuture.get() + cameraProvider = provider val preview = Preview.Builder().build().also { it.setSurfaceProvider(previewView.surfaceProvider) @@ -191,8 +195,8 @@ private class ScannerPlatformView( .also { it.setAnalyzer(analysisExecutor, ::analyze) } try { - cameraProvider.unbindAll() - cameraProvider.bindToLifecycle( + provider.unbindAll() + provider.bindToLifecycle( lifecycleOwner, CameraSelector.DEFAULT_BACK_CAMERA, preview, @@ -238,6 +242,9 @@ private class ScannerPlatformView( override fun getView(): View = previewView override fun dispose() { + disposed = true + cameraProvider?.unbindAll() + cameraProvider = null analysisExecutor.shutdown() } }