0

Every time I exit the scanner camera or scan a QR code I get this warning: SurfaceView - com.example.myapp/com.example.myapp.MainActivity@a9c00b0@0#0 cancelBuffer: BufferQueue has been abandoned

My scanner QR code (all works well):

abstract class QrScannerGenericFragment : Fragment() {
 // UI
 private lateinit var previewView: PreviewView
 private lateinit var scannerProgressBar: ProgressBar
 private lateinit var scannerTextView: TextView
 private lateinit var cameraProvider: ProcessCameraProvider
 private lateinit var analysisUseCase: ImageAnalysis
 private var rgbaBitmap: Bitmap? = null
 private val cameraExecutor by lazy { Executors.newSingleThreadExecutor() }
 private val scanner by lazy {
 val options = BarcodeScannerOptions.Builder()
 .setBarcodeFormats(Barcode.FORMAT_QR_CODE)
 .build()
 BarcodeScanning.getClient(options)
 }
 // HELPERS
 private var scanned = false
 private var infoListener: InfoListener? = null
 // BINDING
 private var _binding: FragmentQrScannerBinding? = null
 private val binding get() = _binding!!
 override fun onAttach(context: Context) {
 super.onAttach(context)
 if (context is InfoListener) {
 infoListener = context
 } else {
 throw RuntimeException("$context must implement InfoListener")
 }
 }
 override fun onCreateView(
 inflater: LayoutInflater,
 parent: ViewGroup?,
 savedInstanceState: Bundle?
 ): View? {
 _binding = FragmentQrScannerBinding.inflate(inflater, parent, false)
 return binding.root
 }
 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
 super.onViewCreated(view, savedInstanceState)
 previewView = binding.scannerPreviewView
 scannerProgressBar = binding.scannerProgressBar
 scannerTextView = binding.scannerTextView
 previewView.previewStreamState.observe(viewLifecycleOwner) { state ->
 when (state) {
 PreviewView.StreamState.IDLE -> {
 scannerProgressBar.visibility = View.VISIBLE
 scannerTextView.visibility = View.GONE
 }
 PreviewView.StreamState.STREAMING -> {
 scannerProgressBar.visibility = View.GONE
 scannerTextView.visibility = View.VISIBLE
 }
 }
 }
 startCamera()
 }
 private fun startCamera() {
 scannerProgressBar.visibility = View.VISIBLE
 val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
 cameraProviderFuture.addListener({
 cameraProvider = cameraProviderFuture.get()
 val previewUseCase = Preview.Builder()
 .build()
 .also { it.setSurfaceProvider(previewView.surfaceProvider) }
 analysisUseCase = ImageAnalysis.Builder()
 .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
 .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
 .build()
 .also { useCase ->
 useCase.setAnalyzer(cameraExecutor) { imageProxy ->
 processImageProxy(imageProxy)
 }
 }
 val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
 cameraProvider.unbindAll()
 cameraProvider.bindToLifecycle(
 viewLifecycleOwner,
 cameraSelector,
 previewUseCase,
 analysisUseCase
 )
 }, ContextCompat.getMainExecutor(requireContext()))
 }
 private fun processImageProxy(imageProxy: ImageProxy) {
 try {
 val width = imageProxy.width
 val height = imageProxy.height
 if (rgbaBitmap == null
 || rgbaBitmap?.width != width
 || rgbaBitmap?.height != height
 ) {
 rgbaBitmap?.recycle()
 rgbaBitmap = createBitmap(width, height)
 }
 val buffer = imageProxy.planes[0].buffer
 buffer.rewind()
 rgbaBitmap!!.copyPixelsFromBuffer(buffer)
 val inputImage =
 InputImage.fromBitmap(rgbaBitmap!!, imageProxy.imageInfo.rotationDegrees)
 scanner.process(inputImage)
 .addOnSuccessListener { barcodes ->
 if (!scanned) {
 barcodes.firstOrNull()?.rawValue?.let { value ->
 scanned = true
 requireActivity().runOnUiThread {
 onQrcodeDetected(value)
 }
 }
 }
 }
 .addOnFailureListener { e ->
 Log.e(LOGCAT_TAG, "Błąd skanowania", e)
 }
 } catch (e: Exception) {
 Log.e(LOGCAT_TAG, "Error processing imageProxy", e)
 } finally {
 imageProxy.close()
 }
 }
 override fun onResume() {
 super.onResume()
 scanned = false
 }
 override fun onStop() {
 if (::cameraProvider.isInitialized) {
 cameraProvider.unbindAll()
 }
 super.onStop()
 }
 override fun onDestroyView() {
 super.onDestroyView()
 if (::cameraProvider.isInitialized) {
 cameraProvider.unbindAll()
 }
 cameraExecutor.shutdown()
 scanner.close()
 rgbaBitmap?.run {
 if (!isRecycled) recycle()
 }
 rgbaBitmap = null
 _binding = null
 }
 protected abstract fun onQrcodeDetected(value: String)
 companion object {
 private const val LOGCAT_TAG = "Debug"
 }
}

I implement listener methods in MainActivity.kt and extends here:

class TrailsQrScannerFragment: QrScannerGenericFragment() {
 private var trailsQrScannerListener: TrailsQrScannerListener? = null
 override fun onAttach(context: Context) {
 super.onAttach(context)
 if(context is TrailsQrScannerListener){
 trailsQrScannerListener = context
 }else {
 throw IllegalStateException("$context must implement TrailsQrScannerListener")
 }
 }
 override fun onQrcodeDetected(scannedText: String) {
 trailsQrScannerListener?.onTrailQrcodeDetected(scannedText)
 }
}

Thanks for your help!

asked Jun 17, 2025 at 10:38
1
  • The solution was to use Handler(Looper.getMainLooper()).post {navigateToCamera()} inside of onRequestPermissionsResult() Commented Jun 25, 2025 at 11:34

1 Answer 1

0

This error might be coming because the the underlying Surface was destroyed or released before the camera instance or renderer expected it to clear. This may not be error and just a warning but you can update the code to following to prevent this error.

private var isShuttingDown = false
private fun processImageProxy(imageProxy: ImageProxy) {
 if (isShuttingDown) {
 imageProxy.close()
 return
 }
 //Rest of the code
 } catch (e: Exception) {
 Log.e(LOGCAT_TAG, "Error processing imageProxy", e)
 imageProxy.close()
 }
}

Mark isShuttingDown = true before unbinding and shutting down the executor:

override fun onStop() {
 isShuttingDown = true
 if (::cameraProvider.isInitialized) {
 cameraProvider.unbindAll()
 }
 super.onStop()
}
override fun onDestroyView() {
 isShuttingDown = true
 if (::cameraProvider.isInitialized) {
 cameraProvider.unbindAll()
 }
 cameraExecutor.shutdownNow() // More aggressive shutdown
 scanner.close()
 rgbaBitmap?.run {
 if (!isRecycled) recycle()
 }
 rgbaBitmap = null
 _binding = null
 super.onDestroyView()
}
answered Jun 17, 2025 at 11:47
Sign up to request clarification or add additional context in comments.

1 Comment

I still get some of the same notifications after i popBack: [SurfaceView[com.my.app/com.my.app.MainActivity]#6(BLAST Consumer)6] (id:2baa00000012,api:4,p:449,c:11178) queueBuffer: BufferQueue has been abandoned

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.