I have the following exception on Galaxy s6 edge device
java.lang.RuntimeException: Camera is being used after Camera.release() was called
at android.hardware.Camera.setPreviewSurface(Native Method)
at android.hardware.Camera.setPreviewDisplay(Camera.java:702)
at com.forsale.forsale.view.uicomponent.qrcode.CameraPreview.surfaceCreated(CameraPreview.java:59)
at android.view.SurfaceView.updateWindow(SurfaceView.java:712)
at android.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.java:316)
at android.view.View.dispatchWindowVisibilityChanged(View.java:10434)
at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1328)
at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1328)
at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1328)
at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1328)
at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1328)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1750)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1437)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7397)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:920)
at android.view.Choreographer.doCallbacks(Choreographer.java:695)
at android.view.Choreographer.doFrame(Choreographer.java:631)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:906)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7224)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
this is my code :
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
private PreviewCallback previewCallback;
private AutoFocusCallback autoFocusCallback;
public CameraPreview(Context context, Camera camera,
PreviewCallback previewCb,
AutoFocusCallback autoFocusCb) {
super(context);
mCamera = camera;
previewCallback = previewCb;
autoFocusCallback = autoFocusCb;
/*
* Set camera to continuous focus if supported, otherwise use
* software auto-focus. Only works for API level >=9.
*/
/*
Camera.Parameters parameters = camera.getParameters();
for (String f : parameters.getSupportedFocusModes()) {
if (f == Parameters.FOCUS_MODE_CONTINUOUS_PICTURE) {
mCamera.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
autoFocusCallback = null;
break;
}
}
*/
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
Log.d("DBG", "Error setting camera preview: " + e.getMessage());
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Camera preview released in activity
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
/*
* If your preview can change or rotate, take care of those events here.
* Make sure to stop the preview before resizing or reformatting it.
*/
if (mHolder.getSurface() == null){
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
try {
// Hard code camera surface rotation 90 degs to match Activity view in portrait
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.setPreviewCallback(previewCallback);
mCamera.startPreview();
mCamera.autoFocus(autoFocusCallback);
} catch (Exception e){
Log.d("DBG", "Error starting camera preview: " + e.getMessage());
}
}
}
this is the code of the activity
public class QRCodeActivity extends BaseActivity
{
private Camera mCamera;
private CameraPreview mPreview;
private Handler mAutoFocusHandler;
private ImageScanner mScanner;
private boolean mBarcodeScanned = false;
private boolean mPreviewing = true;
static {
System.loadLibrary("iconv");
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_qrcode);
initializeActionBar();
setActionBarTitle(getString(R.string.qrcode));
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
mAutoFocusHandler = new Handler();
mCamera = getCameraInstance();
mScanner = new ImageScanner();
mScanner.setConfig(0, Config.X_DENSITY, 3);
mScanner.setConfig(0, Config.Y_DENSITY, 3);
mPreview = new CameraPreview(this, mCamera, previewCb, autoFocusCB);
FrameLayout preview = (FrameLayout)findViewById(R.id.cameraPreview);
preview.addView(mPreview);
}
public void onPause() {
super.onPause();
releaseCamera();
}
public static Camera getCameraInstance(){
Camera c = null;
try {
c = Camera.open();
} catch (Exception e){
}
return c;
}
private void releaseCamera() {
if (mCamera != null) {
mPreviewing = false;
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
}
}
private Runnable doAutoFocus = new Runnable() {
public void run() {
if (mPreviewing)
mCamera.autoFocus(autoFocusCB);
}
};
PreviewCallback previewCb = new PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera camera) {
Parameters parameters = camera.getParameters();
Size size = parameters.getPreviewSize();
Image barcode = new Image(size.width, size.height, "Y800");
barcode.setData(data);
int result = mScanner.scanImage(barcode);
if (result != 0) {
mPreviewing = false;
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
SymbolSet syms = mScanner.getResults();
for (Symbol sym : syms) {
showProgressDialog();
ForSaleServerManager.getInstance().verifyQRCode(QRCodeActivity.this, PhoneUtils.getDeviceId(QRCodeActivity.this) , sym.getData() , new VerifyQRCodeUIListener() {
@Override
public void onVerifyQRCodeCompleted(QRCodeResponse response, AppError error) {
hideProgressDialog();
if (error != null) {
DialogUtils.showDialogMessage(
QRCodeActivity.this,
getString(R.string.error),
PhoneUtils.getErrorMessage(QRCodeActivity.this, error),
getString(R.string.ok), null);
} else {
if (response != null && response.getError() == null) {
DialogUtils.showDialogMessage(QRCodeActivity.this, getString(R.string.info),
response.getMessage(), getString(R.string.ok), new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
});
} else if (response != null && response.getError() != null) {
DialogUtils.showDialogMessage(
QRCodeActivity.this,
getString(R.string.error),
response.getError().getMessage(),
getString(R.string.ok), null);
}
}
}
});
mBarcodeScanned = true;
}
}
}
};
AutoFocusCallback autoFocusCB = new AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
mAutoFocusHandler.postDelayed(doAutoFocus, 1000);
}
};
@Override
protected void initializeUIComponents() {
}
@Override
protected void initializeUIComponentsData() {
}
@Override
protected void initializeUIComponentsTheme() {
}
@Override
protected void initializeUIComponentsAction() {
}
@Override
public void goodTimeToReleaseMemory() {
/*mCamera = null;
mPreview = null;
mAutoFocusHandler = null;
mScanner = null;*/
Runtime.getRuntime().gc();
finish();
}
}
There is a serious flaw in your code: mCamera.release() is called on every onPause, but Camera.open() is only called onCreate.
This said, it is a bad practice to open camera on the main (UI) thread: this call may take too long on some devices (not on Samsung Galaxy 6) and even cause ANR.
The best practice is to open camera on a background HandlerThread (see https://stackoverflow.com/a/19154438/192373). This will guarantee that the camera callbacks (including onPictureTaken()) don't freeze your UI thread.
At any rate, to keep the mCamera object synchronized with the lifecycle of your activity and its SurfaceView, I recommend to start Camera.open() from surfaceCreated and mCamera.release() - from surfaceDestroyed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With