I am using the com.google.android.gms.vision dependency to scan a QR-code.
The problem I am facing is that it keeps scanning the QR-code again and again. I want it to scan only once.
Here is my code :
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final SurfaceView cameraView = (SurfaceView) findViewById(R.id.camera_view);
final TextView barcodeInfo = (TextView) findViewById(R.id.code_info);
barcodeDetector =
new BarcodeDetector.Builder(this)
.setBarcodeFormats(Barcode.QR_CODE)
.build();
cameraSource = new CameraSource
.Builder(this, barcodeDetector)
.setAutoFocusEnabled(true)
.setRequestedPreviewSize(640, 640)
.build();
cameraView.getHolder().addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
if (ActivityCompat.checkSelfPermission(getApplicationContext(), android.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;
}
cameraSource.start(cameraView.getHolder());
} catch (IOException ie) {
Log.e("CAMERA SOURCE", ie.getMessage());
}
}
#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> barcodes = detections.getDetectedItems();
if (barcodes.size() != 0) {
barcodeInfo.post(new Runnable() { // Use the post method of the TextView
public void run() {
barcodeInfo.setText( // Update the TextView
barcodes.valueAt(0).displayValue
);
QRData = barcodeInfo.getText().toString().trim();
Log.d("TAG", barcodeInfo.getText().toString().trim());
}
});
}
}
});
Just set result and call finish when your scan is completed in that activity. After that you need to catch result in parent activity (onActivityResult).
PS. You need to start QRScanner activity with startActivityForResult.
Edit: If QRScan is the same activity stop camera. And maybe you need to hide that surface.
Cheers :)
Related
This is a part of QR Code scanner app. In the very beginning of the app it asks for camera permission, when i click to allow, app doesn't respond. but from second time, app works correctly. I think the error may be in checking permission. Please help me to find the mistake.
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
cameraSource.start(surfaceView.getHolder());
} else {
ActivityCompat.requestPermissions(MainActivity.this, new
String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);
}
} 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();
}
});
I`m trying to create bar code reader for my app, and it works fine, but the problem is when I keep focusing on QR-Code, it continues to read and never stops!!!
How can I make this happen only once?
In this code, it continues to "Toast" until I close the app, and when I use Intent for for closing the current activity and open another activity, the activity opens several times!!!
Here is the code:
public class BarcodeCaptureActivity extends AppCompatActivity {
private SurfaceView camera_preview;
TextView text;
BarcodeDetector barcodeDetector;
CameraSource cameraSource;
final int requestCameraPermissionID = 1001;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_barcode_capture);
camera_preview = (SurfaceView) findViewById(R.id.camera_preview);
text = (TextView) findViewById(R.id.text);
barcodeDetector = new BarcodeDetector.Builder(this).setBarcodeFormats(Barcode.QR_CODE).build();
cameraSource = new CameraSource.Builder(this, barcodeDetector).setRequestedPreviewSize(640, 480).build();
camera_preview.getHolder().addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(BarcodeCaptureActivity.this, new String[]{Manifest.permission.CAMERA},requestCameraPermissionID);
return;
}
try {
cameraSource.start(camera_preview.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> qrcode = detections.getDetectedItems();
if (qrcode.size() != 0){
text.post(new Runnable() {
#Override
public void run() {
Vibrator vibrator = (Vibrator) getApplicationContext().getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(1000);
text.setText(qrcode.valueAt(0).displayValue);
String title = text.getText().toString();
Toast.makeText(BarcodeCaptureActivity.this, "" + title, Toast.LENGTH_SHORT).show();
finish();
}
});
}
}
});
}
Thank for any help...
UPDATE
Problem solved with adding onDestroy and onPause methods...
#Override
protected void onPause() {
super.onPause();
cameraSource.stop();
}
#Override
protected void onDestroy() {
super.onDestroy();
cameraSource.stop();
}
I came across a weird bug in my app.
I'm using a SurfaceView to allow the user to scan a QR code.
Sometimes it works as expected, but sometimes the SurfaceView remains black.
I've checked other posts, but unfortunately didn't find any relevant one.
Here is a code snippet:
//Called when QR scan is needed
private void tryToScan(){
final BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(this).setBarcodeFormats(Barcode.QR_CODE).build();
final CameraSource cameraSource = new CameraSource.Builder(this, barcodeDetector).setRequestedPreviewSize(256, 256).build();
barcodeDetector.setProcessor(new Detector.Processor<Barcode>() {
#Override
public void release() {}
#Override
public void receiveDetections(Detector.Detections<Barcode> detections) {
final SparseArray<Barcode> codes = detections.getDetectedItems();
if (codes.size() > 0) {//if codes detected
sendQr(codes.valueAt(0).displayValue);//send it
}
}
});
//Adds SurfaceHolder.Callback to SurfaceHolder of SurfaceView by id R.id.scanQr (valid id)
((SurfaceView)findViewById(R.id.scanQr)).getHolder().addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
//Sometimes starts successfully but sometimes stays black
cameraSource.start(holder);
} catch (IOException e) {
e.printStackTrace();
}catch (SecurityException e){
askCameraPermission();
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
public void surfaceDestroyed(SurfaceHolder holder) {
cameraSource.stop();
}
});
}
I am working in an application for Android and I am using a Surface to read a QR code. Checking the resources with Monitor I see a constant increment of the memory from ~7 MB to ~20 MB, then the memory is released and the behavior starts over. I wonder if it is normal or I am missing something.
My code
public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {
TextView barCodeInfo;
SurfaceView cameraSurface;
Button scan;
BarcodeDetector barcodeDetector;
CameraSource cameraSource;
static final int REQUEST_CAMERA_PERMISSION = 1001;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
cameraSurface = (SurfaceView) findViewById(R.id.cameraSurface);
barCodeInfo = (TextView) findViewById(R.id.barCodeResult);
scan = (Button) findViewById(R.id.scan);
scan.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (ActivityCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);
} else {
showCameraPreview();
}
}
});
barcodeDetector = new BarcodeDetector.Builder(this)
.setBarcodeFormats(Barcode.QR_CODE)
.build();
barcodeDetector.setProcessor(new Detector.Processor<Barcode>() {
#Override
public void release() {
}
#Override
public void receiveDetections(Detector.Detections<Barcode> detections) {
final SparseArray<Barcode> barCodes = detections.getDetectedItems();
if (barCodes.size() != 0) {
barCodeInfo.post(new Runnable() { // Use the post method of the TextView
public void run() {
barCodeInfo.setText( // Update the TextView
barCodes.valueAt(0).displayValue
);
}
});
}
}
});
cameraSource = new CameraSource.Builder(this, barcodeDetector)
.setRequestedPreviewSize(200, 200)
.build();
cameraSurface.getHolder().addCallback(this);
}
private void showCameraPreview() {
try {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
cameraSource.start(cameraSurface.getHolder());
}
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
if(cameraSurface != null){
cameraSurface = null;
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
showCameraPreview();
} else {
Toast.makeText(this, "Camera permission was denied", Toast.LENGTH_LONG).show();
}
}
}
Android Monitor
The memory is restored only when I close the application.
Yes, it is completely normal. In the course of app being running, resources are allocated in memory and hence memory usage increases (as shown in the android monitor). System keeps on checking free memory to kick off Garbage Collector to release any unreferenced memory.
BTW, JVM doesn't run garbage collector until it has to, because the garbage collection slows things down quite a bit and thus shouldn't be run very frequently. It runs when there is need of memory to be freed. It is always preferred to delay GC as much as possible.
In the image below, sudden release of memory is due to GC event.
And its a good thing to see that there are not too many GC events because that slows down the app performance.
So if you keep using your app and memory footprints keep on increasing, then GC keeps on freeing them from time to time.
My SurfaceView is not getting destroyed even if onPause of the activity is called.
I am taking care of the thread in
public void surfaceCreated(SurfaceHolder holder) {
if (mGameThread.getState() == Thread.State.TERMINATED) {
createGameThread(getHolder(), getContext());
}
mGameThread.setRunning(true);
mGameThread.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
mGameThread.setRunning(false);
while (retry) {
try {
mGameThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
As an hack I have to check the state of the thread in onResume and if the thread is already terminated, I would finish the activity
protected void onResume() {
Log.d(mLogTag, "onResume()");
super.onResume();
if (mGameThread != null) {
if (mGameThread.getState() == Thread.State.TERMINATED) {
finish();
}
}
}
Unfortunately it is not possible to move the thread handling from surfaceDestroyed and surfaceCreated to onPause() and onResume() of the activity. Is it possible to manually destroy the SurfaceView in the onPause() and recreate it in onResume()?
You can add surface view dynamically on your view.
Example :layout.xml
<FrameLayout
android:id="#+id/fragment_file_videoplayer_surface_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</FrameLayout>
MainActivity.java
FrameLayout fl_surfaceview_container =
(FrameLayout)findViewById(R.id.fragment_file_videoplayer_surface_container);
// Add surfaceView on Framelayout
SurfaceView videoSurface = new SurfaceView(getActivity());
fl_surfaceview_container.addView(videoSurface);
//if remove or destroy surfaceview
fl_surfaceview_container.removeAllViews();
You can add a layout as a parent of the surfaceview, then set visibility of the layout GONE in onPause(), and set VISIBLE in onResume() of the activity.
Yes possible.
First initialize Size
Size currentSurfaceSize;
cameraSurface.getHolder().addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(QR_Reader_Activity.this,
new String[]{Manifest.permission.CAMERA}, RequestCameraPermission);
permission = true;
return;
}
try {
cameraSource.start(cameraSurface.getHolder());
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
currentSurfaceSize = new Size(width, height);
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
onPause();
}
});
where do you want to destroy the surface, use this below code.
if (currentSurfaceSize==null){
cameraSurface = (SurfaceView) cameraSurface.getHolder();
cameraSurface.removeCallbacks((Runnable) cameraSurface);
}