Android General Example

Here we will try to present a simple quick start example. We will try to give focus to a few notable function that we use that we consider important "gotchas" when implementing the barKoder barcode scanner SDK.

createBarkoderConfig #

Firstly, let's create a config function where we will store all our configuration settings, in this case the createBarkoderConfig function initializes and configures the barcode scanner view (bkdView) with necessary settings before scanning can be performed. It sets the configuration using the BarkoderConfig class, passing the current context (this) and a license key.

If the license key is invalid, the scan results will include asterisks. Additionally, it provides a lambda function that logs messages related to licensing to help with debugging or tracking the licensing status.

                    private fun createBarkoderConfig() {
        // In order to perform scanning, config property needs to be set before
        // If license key is not valid you will receive results with asterisks inside
        bkdView.config = BarkoderConfig(this, "LICENSE_KEY") {
            Log.i("Licensing SDK: ", it.message)
        }
    }

            

setActiveBarcodeTypes #

To be able to scan barcode types, we need to activate them. Let's define a setActiveBarcodeTypes function which configures the barcode scanner view (bkdView) to recognize specific types of barcodes.

It demonstrates two ways of enabling barcode decoders:

  1. Enabling multiple barcode types at once by passing an array to the SetEnabledDecoders method. In this example, QR codes and EAN-13 barcodes are enabled.
  2. Enabling individual barcode types by setting their enabled property to true. In this example, the UPC-A barcode type is enabled.

This flexible configuration allows the application to specify exactly which barcode formats should be recognized during scanning, either by setting multiple types at once or by enabling them one by one.

In your use case, usually you will use one of these approaches.

                    private fun setActiveBarcodeTypes() {
        // There is an option to set multiple active barcodes at once as array
        bkdView.config.decoderConfig.SetEnabledDecoders(
            arrayOf(
                Barkoder.DecoderType.QR,
                Barkoder.DecoderType.Ean13
            )
        )
        // or configure them one by one
        bkdView.config.decoderConfig.UpcA.enabled = true
    }
            

setBarkoderSettings #

Next define a function where we will update our settings for the barcode scanner view (bkdView).

In our case we will enable image results and include barcode location within the image, also make the region of interest visible and enable pinch-to-zoom functionality.

Finally, configure the ROI to cover the central 90% of the scanner view.

These configurations enhance the user experience by providing more detailed scan results, interactive zooming, and visual feedback about the scan area.

                    private fun setBarkoderSettings() {
        // These are optional settings, otherwise default values will be used
        bkdView.config.let { config ->
            config.isImageResultEnabled = true
            config.isLocationInImageResultEnabled = true
            config.isRegionOfInterestVisible = true
            config.isPinchToZoomEnabled = true
            config.setRegionOfInterest(5f, 5f, 90f, 90f)
        }
    }
            

onBtnScanningClick #

Attach a function that invokes when clicking our scan button. If the scanner isn't already active we will start the scanning process by calling bkdView.startScanning(this).

Notable mention in this function is our call to updateUI() which we will use to show the results from the scanning process.

                    private fun onBtnScanningClick() {
        if (isScanningActive) {
            bkdView.stopScanning()
        } else {
            // Starting the scanning process and set BarkoderResultCallback where read results will be received
            // @throw NPE if config is not set before
            bkdView.startScanning(this)
        }

        isScanningActive = !isScanningActive
        updateUI()
    }
            

updateUI #

The updateUI function updates the UI based on the state of the scanning process and the results obtained:

  1. Updates the scanning button and start scan text view based on whether scanning is active or if a result image is present.
  2. Displays the barcode type and textual data obtained from the scan result.
  3. Calls a function to show additional result details.
  4. Updates the image view to display the result image if one is provided, and sets its visibility accordingly.

This function ensures that the UI reflects the current state of the scanning process and displays the relevant scan results to the user.

                    private fun updateUI(result: Barkoder.Result? = null, resultImage: Bitmap? = null) {
        if (isScanningActive) {
            txtStartScan.isVisible = false
            btnScanning.backgroundTintList =
                ColorStateList.valueOf(resources.getColor(R.color.primary))
        } else {
            txtStartScan.isVisible = resultImage == null
            btnScanning.backgroundTintList =
                ColorStateList.valueOf(resources.getColor(R.color.black))
        }

        txtResultType.text = result?.barcodeTypeName
        txtResult.text = result?.textualData

        showResultExtras(result)

        imgResult.setImageBitmap(resultImage)
        imgResult.isVisible = resultImage != null
    }
            

showResultExtras #

The showResultExtras function displays additional information from a barcode scan result. It checks if the result object and its extra property are not null and not empty. 

Constructs a string of key-value pairs from the extra map, each on a new line and finally sets the text of txtResultExtras to this constructed string, or to an empty string if there are no extras. 

This function ensures that any additional information from the scan result is displayed to the user in a readable format.

                    private fun showResultExtras(result: Barkoder.Result?) {
        if (result?.extra?.isNotEmpty() == true) {
            val extras = StringBuilder()
            result.extra.forEach {
                extras.append("${it.key}: ").append(it.value).appendLine()
            }
            txtResultExtras.text = extras.toString().trimEnd()
        } else
            txtResultExtras.text = ""
    }
            

showFullResult #

The showFullResult is a helper function. It will probably not be necessary in your use-case, but for our needs we will use it to  display the full result of a barcode scan in a dialog box if the result text is not null or blank  

                    private fun showFullResult() {
        if (!txtResult.text.isNullOrBlank()) {
            MaterialAlertDialogBuilder(this)
                .setTitle(R.string.result_title)
                .setMessage(txtResult.text)
                .setPositiveButton(android.R.string.ok, null)
                .show()
        }
    }
            

onCreate #

Finally let's put all of this in the onCreate function for the MainActivity

                    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        title = "${getString(R.string.app_name)} (v${Barkoder.GetVersion()})"

        txtStartScan = findViewById(R.id.txtViewStartScan)
        imgResult = findViewById(R.id.imageViewResult)
        bkdView = findViewById(R.id.barkoderView)
        cardResult = findViewById(R.id.cardViewResult)
        cardResult.setOnClickListener {
            showFullResult()
        }
        txtResult = findViewById(R.id.textViewResult)
        txtResultType = findViewById(R.id.textViewResultType)
        txtResultExtras = findViewById(R.id.textViewResultExtras)
        btnScanning = findViewById(R.id.buttonScanning)
        btnScanning.setOnClickListener { onBtnScanningClick() }

        createBarkoderConfig()
        setActiveBarcodeTypes()
        setBarkoderSettings()
    }
            

Complete Solution #

In the end, let's merge all of these functions and implement them within our main activity.

This code would go in your main activity, and of course it will be different for your project, but generally it's a good starting point to have.

                import android.content.res.ColorStateList
import android.graphics.Bitmap
import android.os.Bundle
import android.util.Log
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.cardview.widget.CardView
import androidx.core.view.isVisible
import com.barkoder.Barkoder
import com.barkoder.BarkoderConfig
import com.barkoder.BarkoderView
import com.barkoder.interfaces.BarkoderResultCallback
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.floatingactionbutton.FloatingActionButton

class MainActivity : AppCompatActivity(), BarkoderResultCallback {

    private lateinit var txtStartScan: TextView
    private lateinit var imgResult: ImageView
    private lateinit var bkdView: BarkoderView
    private lateinit var cardResult: CardView
    private lateinit var txtResult: TextView
    private lateinit var txtResultType: TextView
    private lateinit var txtResultExtras: TextView
    private lateinit var btnScanning: FloatingActionButton

    private var isScanningActive: Boolean = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        title = "${getString(R.string.app_name)} (v${Barkoder.GetVersion()})"

        txtStartScan = findViewById(R.id.txtViewStartScan)
        imgResult = findViewById(R.id.imageViewResult)
        bkdView = findViewById(R.id.barkoderView)
        cardResult = findViewById(R.id.cardViewResult)
        cardResult.setOnClickListener {
            showFullResult()
        }
        txtResult = findViewById(R.id.textViewResult)
        txtResultType = findViewById(R.id.textViewResultType)
        txtResultExtras = findViewById(R.id.textViewResultExtras)
        btnScanning = findViewById(R.id.buttonScanning)
        btnScanning.setOnClickListener { onBtnScanningClick() }

        createBarkoderConfig()
        setActiveBarcodeTypes()
        setBarkoderSettings()
    }

    override fun onStop() {
        isScanningActive = false
        updateUI()

        super.onStop()
    }

    private fun createBarkoderConfig() {
        // In order to perform scanning, config property needs to be set before
        // If license key is not valid you will receive results with asterisks inside
        bkdView.config = BarkoderConfig(this, "LICENSE_KEY") {
            Log.i("Licensing SDK: ", it.message)
        }
    }

    private fun setActiveBarcodeTypes() {
        // There is an option to set multiple active barcodes at once as array
        bkdView.config.decoderConfig.SetEnabledDecoders(
            arrayOf(
                Barkoder.DecoderType.QR,
                Barkoder.DecoderType.Ean13
            )
        )
        // or configure them one by one
        bkdView.config.decoderConfig.UpcA.enabled = true
    }

    private fun setBarkoderSettings() {
        // These are optional settings, otherwise default values will be used
        bkdView.config.let { config ->
            config.isImageResultEnabled = true
            config.isLocationInImageResultEnabled = true
            config.isRegionOfInterestVisible = true
            config.isPinchToZoomEnabled = true
            config.setRegionOfInterest(5f, 5f, 90f, 90f)
        }
    }

    private fun updateUI(result: Barkoder.Result? = null, resultImage: Bitmap? = null) {
        if (isScanningActive) {
            txtStartScan.isVisible = false
            btnScanning.backgroundTintList =
                ColorStateList.valueOf(resources.getColor(R.color.primary))
        } else {
            txtStartScan.isVisible = resultImage == null
            btnScanning.backgroundTintList =
                ColorStateList.valueOf(resources.getColor(R.color.black))
        }

        txtResultType.text = result?.barcodeTypeName
        txtResult.text = result?.textualData

        showResultExtras(result)

        imgResult.setImageBitmap(resultImage)
        imgResult.isVisible = resultImage != null
    }

    private fun onBtnScanningClick() {
        if (isScanningActive) {
            bkdView.stopScanning()
        } else {
            // Starting the scanning process and set BarkoderResultCallback where read results will be received
            // @throw NPE if config is not set before
            bkdView.startScanning(this)
        }

        isScanningActive = !isScanningActive
        updateUI()
    }

    override fun scanningFinished(results: Array<Barkoder.Result>, thumbnails: Array<Bitmap>, resultImage: Bitmap?) {
        isScanningActive = false

        if (results.isNotEmpty())
            updateUI(results[0], resultImage)
        else
            updateUI()
    }

    private fun showResultExtras(result: Barkoder.Result?) {
        if (result?.extra?.isNotEmpty() == true) {
            val extras = StringBuilder()
            result.extra.forEach {
                extras.append("${it.key}: ").append(it.value).appendLine()
            }
            txtResultExtras.text = extras.toString().trimEnd()
        } else
            txtResultExtras.text = ""
    }

    private fun showFullResult() {
        if (!txtResult.text.isNullOrBlank()) {
            MaterialAlertDialogBuilder(this)
                .setTitle(R.string.result_title)
                .setMessage(txtResult.text)
                .setPositiveButton(android.R.string.ok, null)
                .show()
        }
    }
}
            

To try this example you can get our SDK directly from our github repository

However, as mentioned, the SDK will work without a license but the results will be filled with Asterisks (*). To get full results one would need a license key, which can be obtained from our website.  

Page Contents

History:

close