Issue
I'm attempting to put the CameraPreview defined in the Android Developer Guide onto the ApiDemos/OS/Sensors application screen. Half the time it works as expected. However, every other time I resume this test application (provided I pause it by pressing the device's 'home' icon) the following exception gets logged:
06-13 14:10:17.369: D/SENSORS_TEST(11888): supported preview width x height: 640 x 480 06-13 14:10:17.369: D/SENSORS_TEST(11888): supported preview width x height: 320 x 240 06-13 14:10:17.369: D/SENSORS_TEST(11888): supported preview width x height: 176 x 144 06-13 14:10:17.600: D/dalvikvm(11888): GC_FOR_ALLOC freed 56K, 3% free 9091K/9347K, paused 22ms 06-13 14:10:17.600: I/dalvikvm-heap(11888): Grow heap (frag case) to 9.610MB for 695056-byte allocation 06-13 14:10:17.631: D/dalvikvm(11888): GC_CONCURRENT freed 1K, 3% free 9768K/10055K, paused 2ms+2ms 06-13 14:10:31.510: D/AndroidRuntime(11888): Shutting down VM 06-13 14:10:31.510: W/dalvikvm(11888): threadid=1: thread exiting with uncaught exception (group=0x40a351f8) 06-13 14:10:31.518: E/AndroidRuntime(11888): FATAL EXCEPTION: main 06-13 14:10:31.518: E/AndroidRuntime(11888): java.lang.RuntimeException: Method called after release() 06-13 14:10:31.518: E/AndroidRuntime(11888): at android.hardware.Camera.setPreviewDisplay(Native Method) 06-13 14:10:31.518: E/AndroidRuntime(11888): at android.hardware.Camera.setPreviewDisplay(Camera.java:405) 06-13 14:10:31.518: E/AndroidRuntime(11888): at com.example.sensor.Sensors10Activity$CameraPreview.surfaceCreated(Sensors10Activity.java:221)
06-13 14:10:31.518: E/AndroidRuntime(11888): at android.view.SurfaceView.updateWindow(SurfaceView.java:533) 06-13 14:10:31.518: E/AndroidRuntime(11888): at android.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.java:226) 06-13 14:10:31.518: E/AndroidRuntime(11888): at android.view.View.dispatchWindowVisibilityChanged(View.java:5839) 06-13 14:10:31.518: E/AndroidRuntime(11888): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:945) 06-13 14:10:31.518: E/AndroidRuntime(11888): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:945) 06-13 14:10:31.518: E/AndroidRuntime(11888): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:945) 06-13 14:10:31.518: E/AndroidRuntime(11888): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:945) 06-13 14:10:31.518: E/AndroidRuntime(11888): at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:965) 06-13 14:10:31.518: E/AndroidRuntime(11888): at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2442) 06-13 14:10:31.518: E/AndroidRuntime(11888): at android.os.Handler.dispatchMessage(Handler.java:99) 06-13 14:10:31.518: E/AndroidRuntime(11888): at android.os.Looper.loop(Looper.java:137) 06-13 14:10:31.518: E/AndroidRuntime(11888): at android.app.ActivityThread.main(ActivityThread.java:4424) 06-13 14:10:31.518: E/AndroidRuntime(11888): at java.lang.reflect.Method.invokeNative(Native Method) 06-13 14:10:31.518: E/AndroidRuntime(11888): at java.lang.reflect.Method.invoke(Method.java:511) 06-13 14:10:31.518: E/AndroidRuntime(11888): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) 06-13 14:10:31.518: E/AndroidRuntime(11888): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) 06-13 14:10:31.518: E/AndroidRuntime(11888): at dalvik.system.NativeStart.main(Native Method)
Here's the code, most of it taken directly from the dev guide's camera example and the ApiDemos/OS/Sensors sample. Does anyone see what should be done differently in the Activity lifecycle to avoid the exception that occurs at line 221 (as commented in the code)?
Thanks in advance for checking,
Greg
public class Sensors10Activity extends Activity {
private final String TAG = "SENSORS_TEST";
private SensorManager mSensorManager;
private GraphView mGraphView;
private Camera mCamera;
private CameraPreview mCameraPreview;
public class GraphView extends View implements SensorEventListener {
private Bitmap mBitmap;
private Paint mPaint = new Paint();
private Canvas mCanvas = new Canvas();
private Path mPath = new Path();
private RectF mRect = new RectF();
private float mLastValues[] = new float[3*2];
private float mOrientationValues[] = new float[3];
private int mColors[] = new int[3*2];
private float mLastX;
private float mScale[] = new float[2];
private float mYOffset;
private float mMaxX;
private float mSpeed = 1.0f;
private float mWidth;
private float mHeight;
public GraphView(Context context) {
super(context);
mColors[0] = Color.argb(192, 255, 64, 64);
mColors[1] = Color.argb(192, 64, 128, 64);
mColors[2] = Color.argb(192, 64, 64, 255);
mColors[3] = Color.argb(192, 64, 255, 255);
mColors[4] = Color.argb(192, 128, 64, 128);
mColors[5] = Color.argb(192, 255, 255, 64);
mPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
mRect.set(-0.5f, -0.5f, 0.5f, 0.5f);
mPath.arcTo(mRect, 0, 180);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
mCanvas.setBitmap(mBitmap);
mCanvas.drawColor(0xFFFFFFFF);
mYOffset = h * 0.5f;
mScale[0] = - (h * 0.5f * (1.0f / (SensorManager.STANDARD_GRAVITY * 2)));
mScale[1] = - (h * 0.5f * (1.0f / (SensorManager.MAGNETIC_FIELD_EARTH_MAX)));
mWidth = w;
mHeight = h;
if (mWidth < mHeight) {
mMaxX = w;
} else {
mMaxX = w-50;
}
mLastX = mMaxX;
super.onSizeChanged(w, h, oldw, oldh);
}
@Override
protected void onDraw(Canvas canvas) {
synchronized (this) {
if (mBitmap != null) {
final Paint paint = mPaint;
final Path path = mPath;
final int outer = 0xFFC0C0C0;
final int inner = 0xFFff7010;
if (mLastX >= mMaxX) {
mLastX = 0;
final Canvas cavas = mCanvas;
final float yoffset = mYOffset;
final float maxx = mMaxX;
final float oneG = SensorManager.STANDARD_GRAVITY * mScale[0];
paint.setColor(0xFFAAAAAA);
cavas.drawColor(0xFFFFFFFF);
cavas.drawLine(0, yoffset, maxx, yoffset, paint);
cavas.drawLine(0, yoffset+oneG, maxx, yoffset+oneG, paint);
cavas.drawLine(0, yoffset-oneG, maxx, yoffset-oneG, paint);
}
canvas.drawBitmap(mBitmap, 0, 0, null);
float[] values = mOrientationValues;
if (mWidth < mHeight) {
float w0 = mWidth * 0.333333f;
float w = w0 - 32;
float x = w0*0.5f;
for (int i=0 ; i<3 ; i++) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.translate(x, w*0.5f + 4.0f);
canvas.save(Canvas.MATRIX_SAVE_FLAG);
paint.setColor(outer);
canvas.scale(w, w);
canvas.drawOval(mRect, paint);
canvas.restore();
canvas.scale(w-5, w-5);
paint.setColor(inner);
canvas.rotate(-values[i]);
canvas.drawPath(path, paint);
canvas.restore();
x += w0;
}
} else {
float h0 = mHeight * 0.333333f;
float h = h0 - 32;
float y = h0*0.5f;
for (int i=0 ; i<3 ; i++) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.translate(mWidth - (h*0.5f + 4.0f), y);
canvas.save(Canvas.MATRIX_SAVE_FLAG);
paint.setColor(outer);
canvas.scale(h, h);
canvas.drawOval(mRect, paint);
canvas.restore();
canvas.scale(h-5, h-5);
paint.setColor(inner);
canvas.rotate(-values[i]);
canvas.drawPath(path, paint);
canvas.restore();
y += h0;
}
}
}
}
}
public void onSensorChanged(SensorEvent event) {
//Log.d(TAG, "sensor: " + sensor + ", x: " + values[0] + ", y: " + values[1] + ", z: " + values[2]);
synchronized (this) {
if (mBitmap != null) {
final Canvas canvas = mCanvas;
final Paint paint = mPaint;
if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {
for (int i=0 ; i<3 ; i++) {
mOrientationValues[i] = event.values[i];
}
} else {
float deltaX = mSpeed;
float newX = mLastX + deltaX;
int j = (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) ? 1 : 0;
for (int i=0 ; i<3 ; i++) {
int k = i+j*3;
final float v = mYOffset + event.values[i] * mScale[j];
paint.setColor(mColors[k]);
canvas.drawLine(mLastX, mLastValues[k], newX, v, paint);
mLastValues[k] = v;
}
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mLastX += mSpeed;
}
invalidate();
}
}
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
// 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); // !!! LINE 221: exception occurs here.
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());
}
}
}
//////////////
// LIFE CYCLE
//
/**
* Initialization of the Activity after it is first created. Must at least
* call {@link android.app.Activity#setContentView setContentView()} to
* describe what is to be displayed in the screen.
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
// Be sure to call the super class.
super.onCreate(savedInstanceState);
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
mCamera = Camera.open(1);
mCameraPreview = new CameraPreview(this, mCamera);
mGraphView = new GraphView(this);
// setContentView(mGraphView);
// Create RelativeLayout for layout root.
RelativeLayout relativeLayout = new RelativeLayout(this);
RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.FILL_PARENT,
RelativeLayout.LayoutParams.FILL_PARENT);
// Add GraphView to layout.
RelativeLayout.LayoutParams lpGraph = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.FILL_PARENT,
RelativeLayout.LayoutParams.FILL_PARENT);
mGraphView.setLayoutParams(lpGraph);
relativeLayout.addView(mGraphView);
// Add SurfaceView to layout.
List<Camera.Size> ls = mCamera.getParameters().getSupportedPreviewSizes();
int n = ls.size();
int widthMin = 10000;
int imin = -1;
for (int i=0; i<n; i++) {
Log.d(TAG, "supported preview width x height: " + ls.get(i).width + " x " + ls.get(i).height);
if (widthMin > ls.get(i).width) {
widthMin = ls.get(i).width;
imin = i;
}
}
if (imin >= 0) {
RelativeLayout.LayoutParams lpSurface = new RelativeLayout.LayoutParams(
ls.get(imin).width, ls.get(imin).height);
lpSurface.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
lpSurface.addRule(RelativeLayout.CENTER_HORIZONTAL);
mCameraPreview.setLayoutParams(lpSurface);
relativeLayout.addView(mCameraPreview);
}
// Provide Android framework with layout root.
setContentView(relativeLayout, rlp);
}
@Override
protected void onResume() {
super.onResume();
mSensorManager.registerListener(mGraphView,
mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_FASTEST);
mSensorManager.registerListener(mGraphView,
mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
SensorManager.SENSOR_DELAY_FASTEST);
mSensorManager.registerListener(mGraphView,
mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
SensorManager.SENSOR_DELAY_FASTEST);
if (mCamera == null)
mCamera = Camera.open(1);
if (mCameraPreview == null)
mCameraPreview = new CameraPreview(this, mCamera);
}
@Override
protected void onPause() {
super.onPause();
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release(); // release the camera for other applications
mCamera = null;
}
if (mCameraPreview != null) {
mCameraPreview = null;
}
}
@Override
protected void onStop() {
mSensorManager.unregisterListener(mGraphView);
super.onStop();
}
}
Solution
After a couple hours of trial and error, it seems that these lifecycle handlers work (i.e., they handle the pause caused by the power button, the stop caused by the home icon, the destroy caused by the back icon, and the camera is released onPause() so as to make it available for the system's camera application).
@Override
protected void onCreate(Bundle savedInstanceState) {
// Be sure to call the super class.
super.onCreate(savedInstanceState);
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
mCamera = Camera.open(1);
mCameraPreview = new CameraPreview(this, mCamera);
mGraphView = new GraphView(this);
// setContentView(mGraphView);
// Create RelativeLayout for layout root.
mLayoutRoot = new RelativeLayout(this);
RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.FILL_PARENT,
RelativeLayout.LayoutParams.FILL_PARENT);
// Add GraphView to layout.
RelativeLayout.LayoutParams lpGraph = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.FILL_PARENT,
RelativeLayout.LayoutParams.FILL_PARENT);
mGraphView.setLayoutParams(lpGraph);
mLayoutRoot.addView(mGraphView);
// Add SurfaceView to layout.
List<Camera.Size> ls = mCamera.getParameters().getSupportedPreviewSizes();
int n = ls.size();
int widthMin = 10000;
int imin = -1;
for (int i=0; i<n; i++) {
Log.d(TAG, "supported preview width x height: " + ls.get(i).width + " x " + ls.get(i).height);
if (widthMin > ls.get(i).width) {
widthMin = ls.get(i).width;
mCameraPreviewSize = ls.get(i);
imin = i;
}
}
if (imin >= 0) {
RelativeLayout.LayoutParams lpSurface = new RelativeLayout.LayoutParams(
ls.get(imin).width, ls.get(imin).height);
lpSurface.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
lpSurface.addRule(RelativeLayout.CENTER_HORIZONTAL);
mCameraPreview.setLayoutParams(lpSurface);
mLayoutRoot.addView(mCameraPreview);
}
// Provide Android framework with layout root.
setContentView(mLayoutRoot, rlp);
Log.d(TAG, "onCreate OUT mCamera, mCameraPreview: " + mCamera + ", " + mCameraPreview);
}
@Override
protected void onStart() {
super.onStart();
Log.d(TAG, "onStart OUT mCamera, mCameraPreview: " + mCamera + ", " + mCameraPreview);
}
@Override
protected void onResume() {
super.onResume();
mSensorManager.registerListener(mGraphView,
mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_FASTEST);
mSensorManager.registerListener(mGraphView,
mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
SensorManager.SENSOR_DELAY_FASTEST);
mSensorManager.registerListener(mGraphView,
mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
SensorManager.SENSOR_DELAY_FASTEST);
if (mCamera == null)
mCamera = Camera.open(1);
if (mCameraPreview == null) {
mCameraPreview = new CameraPreview(this, mCamera);
RelativeLayout.LayoutParams lpCameraPreview = new RelativeLayout.LayoutParams(
mCameraPreviewSize.width, mCameraPreviewSize.height);
lpCameraPreview.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
lpCameraPreview.addRule(RelativeLayout.CENTER_HORIZONTAL);
mCameraPreview.setLayoutParams(lpCameraPreview);
mLayoutRoot.addView(mCameraPreview);
}
Log.d(TAG, "onResume OUT mCamera, mCameraPreview: " + mCamera + ", " + mCameraPreview);
}
@Override
protected void onPause() {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release(); // release the camera for other applications
mCamera = null;
}
if (mCameraPreview != null) {
mLayoutRoot.removeView(mCameraPreview);
mCameraPreview = null;
}
super.onPause();
Log.d(TAG, "onPause OUT mCamera, mCameraPreview: " + mCamera + ", " + mCameraPreview);
}
@Override
protected void onStop() {
mSensorManager.unregisterListener(mGraphView);
super.onStop();
Log.d(TAG, "onStop OUT mCamera, mCameraPreview: " + mCamera + ", " + mCameraPreview);
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy OUT mCamera, mCameraPreview: " + mCamera + ", " + mCameraPreview);
}
Answered By - gregS
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.