-2

I am trying to integrate Google code scanner into my Android app.

Calling

Tasks.await(scanner.startScan()).rawValue ?: ""

where scanner is the GmsBarcodeScanner object
throws

java.lang.IllegalStateException: Must not be called on the main application thread

But Google code scanner brings up the camera on the entire screen covering anything underneath.
So where's the problem if my app's UI becomes unresponsive while the QR Code is being scanned?

Will await() prevent the QR Code scanner from launching? If so, why?

I need to stop to get the results before I can proceed.

Kitswas
  • 1,134
  • 1
  • 13
  • 30
  • May I know the reason for the downvote? – Kitswas Jul 17 '23 at 06:35
  • Please read the question carefully. "Google code scanner brings up the camera on the entire screen covering anything underneath. So where's the problem if my app's UI becomes unresponsive while the QR Code is being scanned?" I am NOT asking why `java.lang.IllegalStateException` is thrown and I do NOT want callbacks. – Kitswas Jul 17 '23 at 08:58

1 Answers1

0

You should call the scanner.startScan() function from another suspend function to avoid it from getting executed on the main thread.

Example : A barcode scanner class that has the function to start scan and store the result inside of a StateFlow.

class BarcodeScanner(
    context: Context
) {

    /**
     * From the docs: If you know which barcode formats you expect to read, you can improve the
     * speed of the barcode detector by configuring it to only detect those formats.
     */
    private val options = GmsBarcodeScannerOptions.Builder()
        .setBarcodeFormats(
            Barcode.FORMAT_ALL_FORMATS
        )
        .build()

    private val scanner = GmsBarcodeScanning.getClient(context, options)
    val barCodeResults = MutableStateFlow<String?>(null)

    suspend fun startScan() {
        try {
            val result = scanner.startScan().await()
            barCodeResults.value = result.rawValue
            Timber.d(barCodeResults.value)
        } catch (e: Exception) {
            Log.d("scan error: $e")
        }
    }

Provide the scanner class using dagger hilt

@InstallIn(SingletonComponent::class)
@Module
object AppModules {

    @Provides
    fun provideBarcodeScanner(@ApplicationContext appContext: Context) = BarcodeScanner(appContext)

}

Call the function from your viewModel

class MainViewModel @Inject (barcodeScanner : BarcodeScanner) : ViewModel {

    val scanResult = MutableStateFlow<String?>(null)

    init{

      barcodeScanner.barCodeResults.collect{
              scanResult.value = it
         }
   }

    fun startScanning(){
        lifecycleScope.launch{
              barcodeScanner.startScan()           
        }
    }
}

zaid khan
  • 825
  • 3
  • 11