问题
I am trying to make an app which reads QR images and get the data from the image. I am using the latest version of the google machine learning kit for scan barcodes and following the documentation about this https://developers.google.com/ml-kit/vision/barcode-scanning/android.
However, at the moment that I run the app, I am getting the following crash:
Image error with QR scanner App
I have no idea what's going on with this due I a new with this kind of functionality. This is the code that I am using right now:
package com.google.firebase.codelab.barcode_scanning
import android.os.Bundle
import android.util.Log
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.*
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.mlkit.vision.barcode.Barcode
import com.google.mlkit.vision.barcode.BarcodeScannerOptions
import com.google.mlkit.vision.barcode.BarcodeScanning
import com.google.mlkit.vision.common.InputImage
import kotlinx.android.synthetic.main.activity_main.*
import java.util.concurrent.Executors
class BarcodeScannerActivity : AppCompatActivity() {
private val qrList = arrayListOf<QrCode>()
val adapter = QrCodeAdapter(qrList)
private val executor = Executors.newSingleThreadExecutor()
private val options = BarcodeScannerOptions.Builder()
.setBarcodeFormats(
Barcode.FORMAT_QR_CODE)
.build()
private val scanner = BarcodeScanning.getClient(options)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
rvQrCode.layoutManager = LinearLayoutManager(this)
rvQrCode.adapter = adapter
val imageAnalysisConfig = ImageAnalysisConfig.Builder()
.setImageReaderMode(ImageAnalysis.ImageReaderMode.ACQUIRE_LATEST_IMAGE)
.build()
val imageAnalysis = ImageAnalysis(imageAnalysisConfig)
val previewConfig = PreviewConfig.Builder().apply {
setLensFacing(CameraX.LensFacing.BACK)
}.build()
val preview = Preview(previewConfig)
preview.setOnPreviewOutputUpdateListener {
val parent = cameraView.parent as ViewGroup
parent.removeView(cameraView)
cameraView.surfaceTexture = it.surfaceTexture
parent.addView(cameraView, 0)
}
val analyzer = ImageAnalysis.Analyzer{ imageProxy: ImageProxy?, rotationDegrees: Int ->
imageProxy?.let {
it.image?.let { image ->
val inputImage = InputImage.fromMediaImage(image, rotationDegrees)
runBarcodeScanner(inputImage)
//image.close()
}
}
imageProxy?.close()
}
imageAnalysis.setAnalyzer(executor, analyzer)
CameraX.bindToLifecycle(this, preview, imageAnalysis)
}
private fun runBarcodeScanner(image: InputImage) {
// [START run_detector]
scanner.process(image)
.addOnSuccessListener { barcodes ->
// Task completed successfully
// [START_EXCLUDE]
// [START get_barcodes]
Log.e("SUCCESS..","OK")
for (barcode in barcodes) {
val bounds = barcode.boundingBox
val corners = barcode.cornerPoints
val rawValue = barcode.rawValue
val valueType = barcode.valueType
// See API reference for complete list of supported types
when (valueType) {
Barcode.TYPE_WIFI -> {
val ssid = barcode.wifi!!.ssid
val password = barcode.wifi!!.password
val type = barcode.wifi!!.encryptionType
}
Barcode.TYPE_URL -> {
val title = barcode.url!!.title
val url = barcode.url!!.url
}
}
}
// [END get_barcodes]
// [END_EXCLUDE]
}
.addOnFailureListener {
// Task failed with an exception
// ...
Log.e("ERROR..","ERROR")
}
// [END run_detector]
}
}
The layout xml file is the above:
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextureView
android:id="@+id/cameraView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true" />
<FrameLayout
android:id="@+id/framePreview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<ImageView
android:id="@+id/imagePreview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop" />
<ImageButton
android:id="@+id/btnRetry"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_gravity="center"
android:background="@null"
android:scaleType="centerCrop"
android:src="@drawable/ic_refresh" />
</FrameLayout>
<LinearLayout
android:id="@+id/layout_bottom_sheet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FAFAFA"
android:orientation="vertical"
app:layout_behavior="@string/bottom_sheet_behavior">
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="true"
android:visibility="gone" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="Detected Barcodes"
android:textSize="24sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvQrCode"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="8dp"
android:paddingRight="8dp" />
</LinearLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_take_photo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:src="@drawable/ic_camera"
app:backgroundTint="@color/colorPrimary"
app:fabSize="normal"
app:layout_anchor="@id/layout_bottom_sheet"
app:layout_anchorGravity="end"
app:rippleColor="@color/colorAccent" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
And my app grade file is like this:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.google.firebase.codelab.barcode_scanning"
minSdkVersion 21
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
androidExtensions {
experimental = true
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.0.0-rc02'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.13'
androidTestImplementation 'androidx.test:runner:1.3.0-rc01'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0-rc01'
implementation 'com.otaliastudios:cameraview:1.6.0'
implementation "com.google.android.material:material:1.3.0-alpha01"
implementation "androidx.cardview:cardview:1.0.0"
// Barcode model
implementation 'com.google.mlkit:barcode-scanning:16.0.1'
implementation 'androidx.camera:camera-core:1.0.0-alpha06'
implementation 'androidx.camera:camera-camera2:1.0.0-alpha06'
}
Thanks in advance for any help that anyone can give me.
回答1:
So if we look at the code:
- Create InputImage from ImageProxy
- scanner.process(image).addWhateverListener(etc etc) but not onComplete
- imageProxy.close
Why would this not work? Step 2 is async so it takes say a fraction of time before it is executed but in the meantime, step 3 kicks in and clear the image - no image to detect. The solution is to use addOnCompleteListener
to close the image:
scanner.process(image)
.addOnFailureListener { // Some code}
.addOnSuccessListener { // Some more code}
.addOnCompleteListener {
// Close the image
imageProxy.close()}
BTW this got me the first time too and we are thinking about adding better debug message than "Image is already close".
来源:https://stackoverflow.com/questions/63022023/crash-with-android-kotlin-qr-scanner-app-and-the-latest-version-of-google-ml-kit