Error : "Camera: Failed to set already detached use case active"
Error : "Camera: Failed to set already detached use case active"
正在尝试将 CameraX 与 Firebase Barcode Scanner 结合使用来扫描条码。
出现以下错误:
Camera: Failed to set already detached use case active
库版本:
// 相机 X
cameraXVersion = "1.0.0-beta02"
// 相机视图版本
cameraViewVersion = "1.0.0-alpha08"
// Firebase ML 愿景
firebaseMlVisionVersion = "24.0.1"
// Firebase ML 视觉条码模型
firebaseMlVisionBarcodeModelVersion = "16.0.2"
条码扫描器:
class BarcodeScanner(
private val previewView: PreviewView,
private val cameraExecutor: ExecutorService,
private val context: Context,
private val lifecycleOwner: LifecycleOwner,
private val qrCodeAnalyser: QrCodeAnalyser
) {
private var screenAspectRatio: Int
private var rotation: Int
private lateinit var cameraProvider: ProcessCameraProvider
private var cameraSelector: CameraSelector
private lateinit var preview: Preview
private lateinit var imageAnalysis: ImageAnalysis
private lateinit var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>
init {
screenAspectRatio = getAspectRatio(previewView)
if (LOGGING_ENABLED) {
Log.e(TAG, "Preview aspect ratio: $screenAspectRatio")
}
rotation = previewView.display.rotation
// Bind the camera provider to the life cycle owner
cameraSelector = CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build()
}
// Declare and bind preview and analysis use cases
fun bindCameraUseCases() {
cameraProviderFuture = ProcessCameraProvider.getInstance(context)
cameraProviderFuture.addListener(Runnable {
// Camera provider
cameraProvider = cameraProviderFuture.get()
// Preview
preview = Preview.Builder()
// We request aspect ratio but no resolution
.setTargetAspectRatio(screenAspectRatio)
// Set initial target rotation
.setTargetRotation(rotation)
.build()
// Attach the viewfinder's surface provider to preview use case
preview.setSurfaceProvider(previewView.previewSurfaceProvider)
// Image analysis
imageAnalysis = ImageAnalysis.Builder()
// We request aspect ratio but no resolution
.setTargetAspectRatio(screenAspectRatio)
// Set initial target rotation, we will have to call this again if rotation changes
// during the lifecycle of this use case
.setTargetRotation(rotation)
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build()
// The analyzer can then be assigned to the instance
.also { it.setAnalyzer(cameraExecutor, qrCodeAnalyser) }
// Must unbind the use-cases before rebinding them
unbindCameraUseCases()
try {
// A variable number of use-cases can be passed here -
// camera provides access to CameraControl & CameraInfo
cameraProvider.bindToLifecycle(
lifecycleOwner, cameraSelector, preview, imageAnalysis
)
} catch (exc: Exception) {
if (LOGGING_ENABLED) {
Log.e(TAG, "Use case binding failed", exc)
}
}
}, ContextCompat.getMainExecutor(context))
}
fun unbindCameraUseCases() {
cameraProvider.unbindAll()
}
// Detecting the most suitable ratio for dimensions provided in @params by counting absolute
// of preview ratio to one of the provided values.
private fun getAspectRatio(previewView: PreviewView): Int {
// Get screen metrics used to setup camera for full screen resolution
val metrics = DisplayMetrics().also { previewView.display.getRealMetrics(it) }
if (LOGGING_ENABLED) {
Log.e(TAG, "Screen metrics: ${metrics.widthPixels} x ${metrics.heightPixels}")
}
val width = metrics.widthPixels
val height = metrics.heightPixels
val previewRatio = max(width, height).toDouble() / min(width, height)
if (abs(previewRatio - RATIO_4_3_VALUE) <= abs(previewRatio - RATIO_16_9_VALUE)) {
return AspectRatio.RATIO_4_3
}
return AspectRatio.RATIO_16_9
}
companion object {
private const val RATIO_4_3_VALUE = 4.0 / 3.0
private const val RATIO_16_9_VALUE = 16.0 / 9.0
private const val TAG = "Barcode Scanner"
private val LOGGING_ENABLED = BuildConfig.DEBUG && loggingEnabled && barcodeLoggingEnabled
}
}
布局XML:
<androidx.camera.view.PreviewView
android:id="@+id/view_finder"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
由约束布局包裹。
片段代码:
private lateinit var barcodeScanner: BarcodeScanner
private val cameraExecutor = Executors.newSingleThreadExecutor()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
startBarcodeScanner()
}
private fun startBarcodeScanner() {
val qrCodeAnalyser = QrCodeAnalyser { qrCodes ->
qrCodes.forEach { qrCode ->
qrCode.rawValue?.let { qrCodeValue ->
Log.e(TAG, "QR Code detected: ${qrCode.rawValue}.")
// Use case is to detect only the first QR code and then process it and navigate to next fragment
if (::barcodeScanner.isInitialized) {
barcodeScanner.unbindCameraUseCases()
}
// Shut down our background executor
cameraExecutor.shutdown()
}
}
}
barcodeScanner = BarcodeScanner(
view_finder,
cameraExecutor,
requireContext(),
viewLifecycleOwner,
qrCodeAnalyser
)
view_finder.post {
barcodeScanner.bindCameraUseCases()
}
}
override fun onPause() {
super.onPause()
if (::barcodeScanner.isInitialized) {
barcodeScanner.unbindCameraUseCases()
}
}
override fun onResume() {
super.onResume()
view_finder.post {
if (::barcodeScanner.isInitialized) {
barcodeScanner.bindCameraUseCases()
}
}
}
override fun onDestroyView() {
super.onDestroyView()
if (::barcodeScanner.isInitialized) {
barcodeScanner.unbindCameraUseCases()
}
// Shut down our background executor
cameraExecutor.shutdown()
}
所有不相关的代码都被剥离。
收到错误信息时的场景:
当我第二次及以后导航到该片段时。第一次没有报错。
感谢任何帮助。
附上完整的堆栈跟踪:
D/Camera: Use cases [Preview:androidx.camera.core.Preview-2b628f3b-651e-4185-8816-bacd182d7739, ImageAnalysis:androidx.camera.core.ImageAnalysis-16478fc0-c1ff-4cac-9fa0-46e218202cee] now ONLINE for camera 0
D/UseCaseAttachState: Active and online use case: [] for camera: 0
D/Camera: Resetting Capture Session
D/Camera: releasing session in state INITIALIZED
D/Camera: Transitioning camera internal state: INITIALIZED -- OPENING
D/Camera: Opening camera: 0
D/UseCaseAttachState: All use case: [androidx.camera.core.ImageAnalysis-16478fc0-c1ff-4cac-9fa0-46e218202cee, androidx.camera.core.Preview-2b628f3b-651e-4185-8816-bacd182d7739] for camera: 0
I/CameraManager: Using legacy camera HAL.
I/art: Background partial concurrent mark sweep GC freed 26391(1116KB) AllocSpace objects, 27(17MB) LOS objects, 40% free, 20MB/33MB, paused 7.112ms total 172.514ms
D/Camera: Use case ImageAnalysis:androidx.camera.core.ImageAnalysis-16478fc0-c1ff-4cac-9fa0-46e218202cee ACTIVE for camera 0
E/Camera: Failed to set already detached use case active
D/Camera: Use case Preview:androidx.camera.core.Preview-2b628f3b-651e-4185-8816-bacd182d7739 ACTIVE for camera 0
E/Camera: Failed to set already detached use case active
D/Camera: Use cases [ImageAnalysis:androidx.camera.core.ImageAnalysis-16478fc0-c1ff-4cac-9fa0-46e218202cee] now OFFLINE for camera 0
D/UseCaseAttachState: Active and online use case: [] for camera: 0
D/Camera: Resetting Capture Session
D/Camera: releasing session in state OPENING
D/Camera: Use case Preview:androidx.camera.core.Preview-2b628f3b-651e-4185-8816-bacd182d7739 INACTIVE for camera 0
D/UseCaseAttachState: Active and online use case: [] for camera: 0
D/Camera: Use cases [Preview:androidx.camera.core.Preview-2b628f3b-651e-4185-8816-bacd182d7739] now OFFLINE for camera 0
D/Camera: Resetting Capture Session
D/Camera: releasing session in state OPENING
D/Camera: Closing camera: 0
D/Camera: Transitioning camera internal state: OPENING -- CLOSING
D/UseCaseAttachState: Active and online use case: [] for camera: 0
D/UseCaseAttachState: Active and online use case: [] for camera: 0
D/Camera: Use cases [ImageAnalysis:androidx.camera.core.ImageAnalysis-e1f008e1-b782-4a19-940a-e75166d230a5, Preview:androidx.camera.core.Preview-4021921f-00eb-46dd-bce5-fb77d209bd34] now ONLINE for camera 0
D/UseCaseAttachState: Active and online use case: [] for camera: 0
D/Camera: Resetting Capture Session
D/Camera: releasing session in state CLOSING
D/Camera: Transitioning camera internal state: CLOSING -- REOPENING
D/Camera: Use case ImageAnalysis:androidx.camera.core.ImageAnalysis-e1f008e1-b782-4a19-940a-e75166d230a5 ACTIVE for camera 0
D/UseCaseAttachState: Active and online use case: [androidx.camera.core.ImageAnalysis-e1f008e1-b782-4a19-940a-e75166d230a5] for camera: 0
D/Camera: Use case Preview:androidx.camera.core.Preview-4021921f-00eb-46dd-bce5-fb77d209bd34 ACTIVE for camera 0
D/UseCaseAttachState: Active and online use case: [androidx.camera.core.Preview-4021921f-00eb-46dd-bce5-fb77d209bd34, androidx.camera.core.ImageAnalysis-e1f008e1-b782-4a19-940a-e75166d230a5] for camera: 0
D/Camera: CameraDevice.onOpened(): 0
D/Camera: Transitioning camera internal state: REOPENING -- OPENED
D/UseCaseAttachState: All use case: [androidx.camera.core.Preview-4021921f-00eb-46dd-bce5-fb77d209bd34, androidx.camera.core.ImageAnalysis-e1f008e1-b782-4a19-940a-e75166d230a5] for camera: 0
D/CaptureSession: Opening capture session.
I/CameraDeviceState: Legacy camera service transitioning to state CONFIGURING
I/RequestThread-0: Configure outputs: 2 surfaces configured.
D/Camera: app passed NULL surface
I/CameraDeviceState: Legacy camera service transitioning to state IDLE
D/CaptureSession: Attempting to send capture request onConfigured
D/CaptureSession: Issuing request for session.
I/RequestQueue: Repeating capture request set.
D/CaptureSession: CameraCaptureSession.onConfigured() mState=OPENED
D/CaptureSession: CameraCaptureSession.onReady() OPENED
W/LegacyRequestMapper: convertRequestMetadata - control.awbRegions setting is not supported, ignoring value
W/LegacyRequestMapper: Only received metering rectangles with weight 0.
W/LegacyRequestMapper: Only received metering rectangles with weight 0.
I/art: Background partial concurrent mark sweep GC freed 12590(707KB) AllocSpace objects, 1(608KB) LOS objects, 40% free, 20MB/34MB, paused 2.229ms total 165.276ms
I/CameraDeviceState: Legacy camera service transitioning to state CAPTURING
我在 Google 问题跟踪器中创建了一个问题:
https://issuetracker.google.com/issues/154422490?enable_mat=true
响应:
Thanks for filing this issue, this issue can be safely ignored - we have a todo for removing unnecessarily logging. This should be fixed shortly.
正在尝试将 CameraX 与 Firebase Barcode Scanner 结合使用来扫描条码。
出现以下错误:
Camera: Failed to set already detached use case active
库版本:
// 相机 X
cameraXVersion = "1.0.0-beta02"
// 相机视图版本
cameraViewVersion = "1.0.0-alpha08"
// Firebase ML 愿景
firebaseMlVisionVersion = "24.0.1"
// Firebase ML 视觉条码模型
firebaseMlVisionBarcodeModelVersion = "16.0.2"
条码扫描器:
class BarcodeScanner(
private val previewView: PreviewView,
private val cameraExecutor: ExecutorService,
private val context: Context,
private val lifecycleOwner: LifecycleOwner,
private val qrCodeAnalyser: QrCodeAnalyser
) {
private var screenAspectRatio: Int
private var rotation: Int
private lateinit var cameraProvider: ProcessCameraProvider
private var cameraSelector: CameraSelector
private lateinit var preview: Preview
private lateinit var imageAnalysis: ImageAnalysis
private lateinit var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>
init {
screenAspectRatio = getAspectRatio(previewView)
if (LOGGING_ENABLED) {
Log.e(TAG, "Preview aspect ratio: $screenAspectRatio")
}
rotation = previewView.display.rotation
// Bind the camera provider to the life cycle owner
cameraSelector = CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build()
}
// Declare and bind preview and analysis use cases
fun bindCameraUseCases() {
cameraProviderFuture = ProcessCameraProvider.getInstance(context)
cameraProviderFuture.addListener(Runnable {
// Camera provider
cameraProvider = cameraProviderFuture.get()
// Preview
preview = Preview.Builder()
// We request aspect ratio but no resolution
.setTargetAspectRatio(screenAspectRatio)
// Set initial target rotation
.setTargetRotation(rotation)
.build()
// Attach the viewfinder's surface provider to preview use case
preview.setSurfaceProvider(previewView.previewSurfaceProvider)
// Image analysis
imageAnalysis = ImageAnalysis.Builder()
// We request aspect ratio but no resolution
.setTargetAspectRatio(screenAspectRatio)
// Set initial target rotation, we will have to call this again if rotation changes
// during the lifecycle of this use case
.setTargetRotation(rotation)
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build()
// The analyzer can then be assigned to the instance
.also { it.setAnalyzer(cameraExecutor, qrCodeAnalyser) }
// Must unbind the use-cases before rebinding them
unbindCameraUseCases()
try {
// A variable number of use-cases can be passed here -
// camera provides access to CameraControl & CameraInfo
cameraProvider.bindToLifecycle(
lifecycleOwner, cameraSelector, preview, imageAnalysis
)
} catch (exc: Exception) {
if (LOGGING_ENABLED) {
Log.e(TAG, "Use case binding failed", exc)
}
}
}, ContextCompat.getMainExecutor(context))
}
fun unbindCameraUseCases() {
cameraProvider.unbindAll()
}
// Detecting the most suitable ratio for dimensions provided in @params by counting absolute
// of preview ratio to one of the provided values.
private fun getAspectRatio(previewView: PreviewView): Int {
// Get screen metrics used to setup camera for full screen resolution
val metrics = DisplayMetrics().also { previewView.display.getRealMetrics(it) }
if (LOGGING_ENABLED) {
Log.e(TAG, "Screen metrics: ${metrics.widthPixels} x ${metrics.heightPixels}")
}
val width = metrics.widthPixels
val height = metrics.heightPixels
val previewRatio = max(width, height).toDouble() / min(width, height)
if (abs(previewRatio - RATIO_4_3_VALUE) <= abs(previewRatio - RATIO_16_9_VALUE)) {
return AspectRatio.RATIO_4_3
}
return AspectRatio.RATIO_16_9
}
companion object {
private const val RATIO_4_3_VALUE = 4.0 / 3.0
private const val RATIO_16_9_VALUE = 16.0 / 9.0
private const val TAG = "Barcode Scanner"
private val LOGGING_ENABLED = BuildConfig.DEBUG && loggingEnabled && barcodeLoggingEnabled
}
}
布局XML:
<androidx.camera.view.PreviewView
android:id="@+id/view_finder"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
由约束布局包裹。
片段代码:
private lateinit var barcodeScanner: BarcodeScanner
private val cameraExecutor = Executors.newSingleThreadExecutor()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
startBarcodeScanner()
}
private fun startBarcodeScanner() {
val qrCodeAnalyser = QrCodeAnalyser { qrCodes ->
qrCodes.forEach { qrCode ->
qrCode.rawValue?.let { qrCodeValue ->
Log.e(TAG, "QR Code detected: ${qrCode.rawValue}.")
// Use case is to detect only the first QR code and then process it and navigate to next fragment
if (::barcodeScanner.isInitialized) {
barcodeScanner.unbindCameraUseCases()
}
// Shut down our background executor
cameraExecutor.shutdown()
}
}
}
barcodeScanner = BarcodeScanner(
view_finder,
cameraExecutor,
requireContext(),
viewLifecycleOwner,
qrCodeAnalyser
)
view_finder.post {
barcodeScanner.bindCameraUseCases()
}
}
override fun onPause() {
super.onPause()
if (::barcodeScanner.isInitialized) {
barcodeScanner.unbindCameraUseCases()
}
}
override fun onResume() {
super.onResume()
view_finder.post {
if (::barcodeScanner.isInitialized) {
barcodeScanner.bindCameraUseCases()
}
}
}
override fun onDestroyView() {
super.onDestroyView()
if (::barcodeScanner.isInitialized) {
barcodeScanner.unbindCameraUseCases()
}
// Shut down our background executor
cameraExecutor.shutdown()
}
所有不相关的代码都被剥离。
收到错误信息时的场景:
当我第二次及以后导航到该片段时。第一次没有报错。
感谢任何帮助。
附上完整的堆栈跟踪:
D/Camera: Use cases [Preview:androidx.camera.core.Preview-2b628f3b-651e-4185-8816-bacd182d7739, ImageAnalysis:androidx.camera.core.ImageAnalysis-16478fc0-c1ff-4cac-9fa0-46e218202cee] now ONLINE for camera 0
D/UseCaseAttachState: Active and online use case: [] for camera: 0
D/Camera: Resetting Capture Session
D/Camera: releasing session in state INITIALIZED
D/Camera: Transitioning camera internal state: INITIALIZED -- OPENING
D/Camera: Opening camera: 0
D/UseCaseAttachState: All use case: [androidx.camera.core.ImageAnalysis-16478fc0-c1ff-4cac-9fa0-46e218202cee, androidx.camera.core.Preview-2b628f3b-651e-4185-8816-bacd182d7739] for camera: 0
I/CameraManager: Using legacy camera HAL.
I/art: Background partial concurrent mark sweep GC freed 26391(1116KB) AllocSpace objects, 27(17MB) LOS objects, 40% free, 20MB/33MB, paused 7.112ms total 172.514ms
D/Camera: Use case ImageAnalysis:androidx.camera.core.ImageAnalysis-16478fc0-c1ff-4cac-9fa0-46e218202cee ACTIVE for camera 0
E/Camera: Failed to set already detached use case active
D/Camera: Use case Preview:androidx.camera.core.Preview-2b628f3b-651e-4185-8816-bacd182d7739 ACTIVE for camera 0
E/Camera: Failed to set already detached use case active
D/Camera: Use cases [ImageAnalysis:androidx.camera.core.ImageAnalysis-16478fc0-c1ff-4cac-9fa0-46e218202cee] now OFFLINE for camera 0
D/UseCaseAttachState: Active and online use case: [] for camera: 0
D/Camera: Resetting Capture Session
D/Camera: releasing session in state OPENING
D/Camera: Use case Preview:androidx.camera.core.Preview-2b628f3b-651e-4185-8816-bacd182d7739 INACTIVE for camera 0
D/UseCaseAttachState: Active and online use case: [] for camera: 0
D/Camera: Use cases [Preview:androidx.camera.core.Preview-2b628f3b-651e-4185-8816-bacd182d7739] now OFFLINE for camera 0
D/Camera: Resetting Capture Session
D/Camera: releasing session in state OPENING
D/Camera: Closing camera: 0
D/Camera: Transitioning camera internal state: OPENING -- CLOSING
D/UseCaseAttachState: Active and online use case: [] for camera: 0
D/UseCaseAttachState: Active and online use case: [] for camera: 0
D/Camera: Use cases [ImageAnalysis:androidx.camera.core.ImageAnalysis-e1f008e1-b782-4a19-940a-e75166d230a5, Preview:androidx.camera.core.Preview-4021921f-00eb-46dd-bce5-fb77d209bd34] now ONLINE for camera 0
D/UseCaseAttachState: Active and online use case: [] for camera: 0
D/Camera: Resetting Capture Session
D/Camera: releasing session in state CLOSING
D/Camera: Transitioning camera internal state: CLOSING -- REOPENING
D/Camera: Use case ImageAnalysis:androidx.camera.core.ImageAnalysis-e1f008e1-b782-4a19-940a-e75166d230a5 ACTIVE for camera 0
D/UseCaseAttachState: Active and online use case: [androidx.camera.core.ImageAnalysis-e1f008e1-b782-4a19-940a-e75166d230a5] for camera: 0
D/Camera: Use case Preview:androidx.camera.core.Preview-4021921f-00eb-46dd-bce5-fb77d209bd34 ACTIVE for camera 0
D/UseCaseAttachState: Active and online use case: [androidx.camera.core.Preview-4021921f-00eb-46dd-bce5-fb77d209bd34, androidx.camera.core.ImageAnalysis-e1f008e1-b782-4a19-940a-e75166d230a5] for camera: 0
D/Camera: CameraDevice.onOpened(): 0
D/Camera: Transitioning camera internal state: REOPENING -- OPENED
D/UseCaseAttachState: All use case: [androidx.camera.core.Preview-4021921f-00eb-46dd-bce5-fb77d209bd34, androidx.camera.core.ImageAnalysis-e1f008e1-b782-4a19-940a-e75166d230a5] for camera: 0
D/CaptureSession: Opening capture session.
I/CameraDeviceState: Legacy camera service transitioning to state CONFIGURING
I/RequestThread-0: Configure outputs: 2 surfaces configured.
D/Camera: app passed NULL surface
I/CameraDeviceState: Legacy camera service transitioning to state IDLE
D/CaptureSession: Attempting to send capture request onConfigured
D/CaptureSession: Issuing request for session.
I/RequestQueue: Repeating capture request set.
D/CaptureSession: CameraCaptureSession.onConfigured() mState=OPENED
D/CaptureSession: CameraCaptureSession.onReady() OPENED
W/LegacyRequestMapper: convertRequestMetadata - control.awbRegions setting is not supported, ignoring value
W/LegacyRequestMapper: Only received metering rectangles with weight 0.
W/LegacyRequestMapper: Only received metering rectangles with weight 0.
I/art: Background partial concurrent mark sweep GC freed 12590(707KB) AllocSpace objects, 1(608KB) LOS objects, 40% free, 20MB/34MB, paused 2.229ms total 165.276ms
I/CameraDeviceState: Legacy camera service transitioning to state CAPTURING
我在 Google 问题跟踪器中创建了一个问题:
https://issuetracker.google.com/issues/154422490?enable_mat=true
响应:
Thanks for filing this issue, this issue can be safely ignored - we have a todo for removing unnecessarily logging. This should be fixed shortly.