javaandroidfirebaseqr-codegoogle-vision

How to set Google Vision QR Scanner to detect only one value?


I have implemented a QR scanner(QRScanner class) using Google Vision API. Once a value is detected it is passed to another activity(Info class) using Intents. The problem is that once a QR code is scanned the Info class gets opened several times.I want to limit the QRScanner class to get only one QR value and Info classed to be opened only once.

QRScanner Class

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_qr_scanner);

cameraPreview = (SurfaceView) findViewById(R.id.camera_surface);
qrResult = (TextView) findViewById(R.id.scannerResult);
setupCamera();
}

private void setupCamera() {

BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(this).setBarcodeFormats(Barcode.QR_CODE).build();
final CameraSource cameraSource = new CameraSource.Builder(this, barcodeDetector)
        .setAutoFocusEnabled(true)
        .setRequestedPreviewSize(1600, 1024)
        .build();

cameraPreview.getHolder().addCallback(new SurfaceHolder.Callback() {
    @Override
    public void surfaceCreated(SurfaceHolder holder) {

        if (ActivityCompat.checkSelfPermission(QrScanner.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
            return;
        }
        try {
            cameraSource.start(cameraPreview.getHolder());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        cameraSource.stop();
    }
});


barcodeDetector.setProcessor(new Detector.Processor<Barcode>() {
    @Override
    public void release() {

    }

    @Override
    public void receiveDetections(Detector.Detections<Barcode> detections) {

        final SparseArray<Barcode> qrCodes = detections.getDetectedItems();

        if(qrCodes.size()>0)
        {
            qrResult.post(new Runnable() {
                @Override
                public void run() {

                    qrResult.setText(qrCodes.valueAt(0).displayValue);
                    Intent intent = new Intent(QrScanner.this,Info.class);
                    intent.putExtra(QR_CODE,qrCodes.valueAt(0).displayValue);
                    startActivity(intent);
                }
            });
        }
    }
});
}

Info Class

Intent intent = getIntent();
QRCODE = (String) intent.getStringExtra(QrScanner.QR_CODE);

DB = FirebaseDatabase.getInstance();
ref = DB.getReference().child("Animals").child(QRCODE);
ref.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

        String DBAnimalClass = dataSnapshot.child("class").getValue().toString();
        String DBAnimalFamily = dataSnapshot.child("family").getValue().toString();
        String DBAnimalOrder = dataSnapshot.child("order").getValue().toString();

    }

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {

    }
});

Currently once a QR is detected the Info class gets called several times. I want the QRScanner to get only one value and Info class to get called only once.


Solution

  • After some research I found out how to fix this. However after coming back to this activity by pressing the back button from the activity loaded through intent, the scanner wont work anymore therefore the onCreate() method should be reloaded.

    working code

    if (qrCodes.size() > 0) {
        barcodeDetector.release(); //stops the scanner from reading multiple values
        qrResult.post(new Runnable() {
            @Override
            public void run() {
                qrResult.setText(qrCodes.valueAt(0).displayValue);
                Intent intent = new Intent(QrScanner.this,Info.class);
                intent.putExtra(QR_CODE,qrCodes.valueAt(0).displayValue);
                startActivity(intent);
            }
        });
    }
    

    The reason cameraSource.stop() won't work is explained in this link; https://stackoverflow.com/a/41024780/6737536

    hope it helps!!