I am taking pictures in the background inside my Android App. However it gives an error:
02-09 15:22:12.061: E/cheeta(28633): timer testing
02-09 15:22:13.546: W/System.err(28633): java.lang.RuntimeException: takePicture failed
02-09 15:22:13.546: W/System.err(28633): at android.hardware.Camera.native_takePicture(Native Method)
02-09 15:22:13.546: W/System.err(28633): at android.hardware.Camera.takePicture(Camera.java:1194)
02-09 15:22:13.551: W/System.err(28633): at cam.sharp.MainActivity$MyTimerTask.run(MainActivity.java:69)
02-09 15:22:13.551: W/System.err(28633): at java.util.Timer$TimerImpl.run(Timer.java:284)
02-09 15:22:13.551: E/cheeta(28633): timer testing
02-09 15:22:15.051: W/System.err(28633): java.lang.RuntimeException: takePicture failed
02-09 15:22:15.051: W/System.err(28633): at android.hardware.Camera.native_takePicture(Native Method)
02-09 15:22:15.051: W/System.err(28633): at android.hardware.Camera.takePicture(Camera.java:1194)
02-09 15:22:15.051: W/System.err(28633): at cam.sharp.MainActivity$MyTimerTask.run(MainActivity.java:69)
02-09 15:22:15.051: W/System.err(28633): at java.util.Timer$TimerImpl.run(Timer.java:284)
02-09 15:22:15.051: E/cheeta(28633): timer testing
02-09 15:22:16.551: W/System.err(28633): java.lang.RuntimeException: takePicture failed
02-09 15:22:16.556: W/System.err(28633): at android.hardware.Camera.native_takePicture(Native Method)
02-09 15:22:16.556: W/System.err(28633): at android.hardware.Camera.takePicture(Camera.java:1194)
02-09 15:22:16.561: W/System.err(28633): at cam.sharp.MainActivity$MyTimerTask.run(MainActivity.java:69)
02-09 15:22:16.561: W/System.err(28633): at java.util.Timer$TimerImpl.run(Timer.java:284)
02-09 15:22:16.561: E/cheeta(28633): timer testing
I have two files.
MainActivity.java and CameraPreview.java
Here is the code for both.
MainActivity.java
package cam.sharp;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.content.Context;
import android.hardware.Camera;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.widget.FrameLayout;
import android.widget.Toast;
public class MainActivity extends Activity {
private int cameraId = 0;
private Camera mCamera;
private CameraPreview mPreview;
String fileName = "tempImage.jpeg";
File file;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Create an instance of Camera
mCamera = getCameraInstance(cameraId);
if (mCamera == null) {
Toast.makeText(
getApplicationContext(),
"The camera service is currently unavailable, please try again!",
Toast.LENGTH_LONG).show();
finish();
} else {
// Create our Preview view and set it as the content of our
// activity.
mPreview = new CameraPreview(this, mCamera);
FrameLayout frameLayout = (FrameLayout) findViewById(R.id.camera_preview);
frameLayout.addView(mPreview);
}
// start thread for these
MyTimerTask myTask = new MyTimerTask();
Timer myTimer = new Timer();
// public void schedule (TimerTask task, long delay, long period)
// Schedule a task for repeated fixed-delay execution after a specific
// delay.
//
// Parameters
// task the task to schedule.
// delay amount of time in milliseconds before first execution.
// period amount of time in milliseconds between subsequent executions.
myTimer.schedule(myTask, 3000, 1500);
}
class MyTimerTask extends TimerTask {
public void run() {
try {
mCamera.takePicture(null, null, null, mPictureCallback);
file = new File(getFilesDir(), fileName);
} catch (Exception e) {
e.printStackTrace();
}
Log.e("cheeta", "timer testing");
}
}
Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
public void onPictureTaken(byte[] imageData, Camera c) {
Log.e("Callback TAG", "Here in jpeg Callback");
if (imageData != null) {
FileOutputStream outputStream;
try {
outputStream = openFileOutput(fileName,
Context.MODE_PRIVATE);
outputStream.write(imageData);
outputStream.close();
// Intent intent = new Intent(SnapScreen.this,
// PreviewScreen.class);
// if (fromMessageReview == true) {
// intent.putExtra("fromMessageReview", "true");
// }
// startActivity(intent);
// overridePendingTransition(R.anim.slide_in,
// R.anim.slide_out);
finish();
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
@Override
protected void onDestroy() {
super.onDestroy();
releaseCamera();
}
/** A safe way to get an instance of the Camera object. */
public static Camera getCameraInstance(int cameraId) {
Camera c = null;
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
c = Camera.open(cameraId);
} else {
c = Camera.open();
}
} catch (Exception e) {
c = null;
}
return c; // returns null if camera is unavailable
}
private void releaseCamera() {
if (mCamera != null) {
mCamera.release(); // release the camera for other applications
mCamera = null;
}
}
}
CameraPreview.java
package cam.sharp;
import java.io.IOException;
import android.annotation.SuppressLint;
import android.content.Context;
import android.hardware.Camera;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
/** A basic Camera preview class */
@SuppressLint("ViewConstructor")
public class CameraPreview extends SurfaceView implements
SurfaceHolder.Callback {
private static final String TAG = "Camera Preview";
private SurfaceHolder mHolder;
public Camera mCamera;
@SuppressWarnings("deprecation")
@SuppressLint("NewApi")
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
mCamera.setDisplayOrientation(90);
// 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);
mCamera.setDisplayOrientation(90);
mCamera.startPreview();
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// 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
}
// set preview size and make any resize, rotate or
// reformatting changes here
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
Can anyone see what is the issue? I am calling mCamera.startPreview(); but still no use.
Thanks
You have 2 problems in your code:
First: In your onPictureTaken
call back you are calling the finish()
method, wich in turn signals that the activity should be destroyed, and calls the onDestroy()
method, wich in turn releases your camera. However your MainActivity.java
is not destroyed (not really sure why, but through logCat, I found that the onCreate()
is only being called once, so I assumed the activity is not destroyed. A possible explanation for this might be that the Timer is controlled by a diferent thread and as such might not be aware that the MainActivity was destroyed, but I can't confirm), and so your myTimer
will continue to run, and when it gets to mCamera.takePicture(null, null, null, mPictureCallback);
it will throw a NullPointException
because the camera was already released, and the MainActivity.onCreate()
wasn't called again to get a new instance to mCamera.
So, to solve the first problem:
Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
public void onPictureTaken(byte[] imageData, Camera c) {
Log.e("Callback TAG", "Here in jpeg Callback");
if (imageData != null) {
FileOutputStream outputStream = null;
try {
outputStream = openFileOutput(fileName, Context.MODE_PRIVATE);
outputStream.write(imageData);
// Removed the finish call you had here
} catch (Exception e) {
e.printStackTrace();
} finally {
if (outputStream != null) try {
outputStream.close();
} catch (IOException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
}
}
}
}
};
Second: Is where you call your startPreview()
method. Accooding to the documentation of takePicture()
:
This method is only valid when preview is active (after startPreview()). Preview will be stopped after the image is taken; callers must call startPreview() again if they want to re-start preview or take more pictures. This should not be called between start() and stop().
You were only calling startPreview()
once, when you create the camera, and because of problem 1, the onCreate()
on MainActivity is only being called once. Since you have a timer taking pictures every 1.5 seconds, you should call startPreview()
before calling takePicture()
, so to solve this:
class MyTimerTask extends TimerTask {
public void run() {
try {
// Call startPreview before taking a picture
mCamera.startPreview();
mCamera.takePicture(null, null, null, mPictureCallback);
file = new File(getFilesDir(), fileName);
} catch (NullPointerException ne) {
ne.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
Log.e("cheeta", "timer testing");
}
}
After this the app continuasly takes pictures, and stores them. I never used a Timer like that so Im not sure how to make it stop. If you only want a small number of pictures taken within each call to the CameraPreview Activity
I suggest you use a Timer with an action listener, like so:
Timer tm = new Timer(1000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// Take x pictures
tm.stop();
}
});
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