4

I'm developing an app that has Barcode Scanner using google mobile vision api. I should be able to scan in ScannerClassy.java only once and save the result in MainActivity. The problem is when I scanned the barcode, it opened MainActivity.java 5-7 times. I tried to use camerasource.release() but it did not work.

ScannerClass.java

    import com.example.MashapeHello.R;
    import com.google.android.gms.vision.Detector;
    import android.Manifest;
    import android.app.Activity;
    import android.content.Intent;
    import android.content.pm.PackageManager;
    import android.os.Looper;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.support.v4.app.ActivityCompat;
    import android.util.Log;
    import android.util.SparseArray;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    import android.widget.TextView;

    import com.google.android.gms.vision.CameraSource;
    import com.google.android.gms.vision.barcode.Barcode;
    import com.google.android.gms.vision.barcode.BarcodeDetector;
    import java.io.IOException;


    public class ScannerClass extends AppCompatActivity implements Detector.Processor {
        private TextView textView;
        private SurfaceView surfaceView;
        private BarcodeDetector barcodeDetector;
        private CameraSource cameraSource;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            surfaceView = (SurfaceView) this.findViewById(R.id.surfaceView);

        barcodeDetector = new BarcodeDetector.Builder(this).setBarcodeFormats(Barcode.ALL_FORMATS).build();
        barcodeDetector.setProcessor(this);

        cameraSource = new CameraSource.Builder(getApplicationContext(), barcodeDetector).
                setRequestedPreviewSize(1024,1024).setAutoFocusEnabled(true)
                .build();

        final Activity activity = this;

        surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                try{
                    if(ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){
                        ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.CAMERA},1024);
                        return;
                    }
                    cameraSource.start(surfaceView.getHolder());
                } catch (IOException ie){
                    Log.e("Camera start problem", ie.getMessage());
                }
            }

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

            }

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


        @Override
        public void release(){

        }


        @Override
        public void receiveDetections(Detector.Detections detections) {
        final SparseArray<Barcode> barcodes = detections.getDetectedItems();
        if (barcodes.size() != 0) {
            final StringBuilder sb = new StringBuilder();
            for (int i = 0; i < barcodes.size(); ++i) {
                sb.append(barcodes.valueAt(i).rawValue).append("\n");
            }
            Intent intent = new Intent(this, MainActivity.class);
            intent.putExtra("barcodevalue", sb.toString());
            startActivity(intent);
            cameraSource.release();


        }
    }
}
Community
  • 1
  • 1
Gina W
  • 45
  • 1
  • 7

2 Answers2

0

You can solve this by creating your own barcode detector class that uses the BarcodeDetector class internally. Here is a simple example:

public class LimitToOneBarcodeDetector extends Detector<Barcode> {

     private BarcodeDetector internalDetector;

     public LimitToOneBarcodeDetector(Context context) {
         this.internalDetector = new BarcodeDetector.Builder(App.getContext())
            .setBarcodeFormats(Barcode.ALL_FORMATS)
            .build();
    }

    @Override
    public SparseArray<Barcode> detect(Frame frame) {

        SparseArray<Barcode> detected = this.internalDetector.detect(frame);

        if (detected == null) {
            // Nothing detected, kick out an empty array 
            return new SparseArray<>();
        }

        if (detected.size() == 0) {
            // Detected size = 0 , kick out an empty array
            return new SparseArray<>();
        }

        if (detected.size() > 1) {
            // Detected more than one barcode, kick out an empty array
            return new SparseArray<>();
        }

        // If we're here, there is only one barcode, return the array
        return detected;
}

Then you would simply replace this line in your Activity:

barcodeDetector = new BarcodeDetector.Builder(this).setBarcodeFormats(Barcode.ALL_FORMATS).build();

With this one or something similar:

barcodeDetector = new LimitToOneBarcodeDetector(this);
ctorx
  • 6,841
  • 8
  • 39
  • 53
0

this issue is, that you keep starting new activities with startActivity(intent);

instead of finishing the current activity with a detection result ...

better start ScannerClass with startActivityForResult() and pass back all the bar-codes:

if (barcodes.size() > 0) {
    cameraSource.release();
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < barcodes.size(); ++i) {
        sb.append(barcodes.valueAt(i).rawValue).append("\n");
    }
    Intent data = new Intent();
    data.putExtra("barcodes", sb.toString());
    this.setResult(AppCompatActivity.RESULT_OK, data);
    this.finish();
}

these can then be processed in method MainActivity.onActivityResult().

Martin Zeitler
  • 1
  • 19
  • 155
  • 216