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:
-
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. -
Enabling individual barcode types by setting their
enabled
property totrue
. 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:
- Updates the scanning button and start scan text view based on whether scanning is active or if a result image is present.
- Displays the barcode type and textual data obtained from the scan result.
- Calls a function to show additional result details.
- 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 the barKoder Developer Portal.