This Android project demonstrates how to continuously capture the camera preview while also listening for barcode scans using the journeyapps/barcodescanner library. This is useful when you want to execute additional processing (like detecting custom patterns) on the camera preview.
Key Components:
build.gradle.kts
:
dependencies {
...
implementation("com.journeyapps:zxing-android-embedded:4.3.0")
...
}
layout.xml: Declares a DecoratedBarcodeView where the camera feed will be displayed.
...
<com.journeyapps.barcodescanner.DecoratedBarcodeView
android:id="@+id/barcodeView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
...
onCreate method: Initializes the camera and starts the periodic preview stealing function.
...
barcodeView = findViewById(R.id.barcodeView)
capture = CaptureManager(this, barcodeView)
capture.initializeFromIntent(intent, savedInstanceState)
capture.decode()
periodicPreviewStealer()
barcodeView.decodeContinuous(object : BarcodeCallback {
override fun barcodeResult(result: BarcodeResult) {
handleResult(result.result.text)
}
override fun possibleResultPoints(resultPoints: List<ResultPoint>) {}
})
...
The preview / periodic stealer method: Uses a Handler to continuously request camera previews, process them, and run custom code (handleResult method) on the main thread if certain conditions are met (in this example, if foxesResult.found is true).
private fun periodicPreviewStealer() {
val handler = Handler(Looper.getMainLooper())
val runnableCode = object : Runnable {
private var hasImagePreview = false
override fun run() {
if (!isCameraPaused) { // class variable, set true when application onPause called for example
barcodeView.barcodeView.cameraInstance.requestPreview(object : PreviewCallback {
override fun onPreview(sourceData: SourceData) {
hasImagePreview = true
val bitmap = sourceData.bitmap
val width = bitmap.width
val height = bitmap.height
val size = width * height
val pixels = IntArray(size)
bitmap.getPixels(pixels, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height)
val foxesResult = detectFoxes(width, height, pixels)
if (foxesResult.found) {
Handler(Looper.getMainLooper()).post {
handleResult(foxesResult)
}
}
Handler(Looper.getMainLooper()).postDelayed({
periodicPreviewStealer()
}, 1000)
}
override fun onPreviewError(e: java.lang.Exception?) {
Log.e("periodicPreviewStealer", "Not yet implemented ${e?.message}")
}
})
}
if (!hasImagePreview) {
Handler(Looper.getMainLooper()).postDelayed({
if (!hasImagePreview) {
handler.postDelayed(this, 1)
}
}, 1000)
}
}
}
handler.post(runnableCode)
}
Important Notes: The variable isCameraPaused should be managed based on your app's lifecycle. For instance, set it to true in onPause() and false in onResume() to ensure the camera preview stealing is paused and resumed appropriately.