android:相机 onPause/onResume 问题
我在 onPause() onResume() 相机直播周期方面遇到了一些麻烦: 带有预览功能的相机和拍照效果都很好。但有一个例外:
我启动应用程序,单击主页按钮,切换回应用程序并拍摄另一张照片。
结果:shuttercallback 仍然执行(参见代码),但 jpeg 回调不再执行!然后我的 Galaxy S 振动,并且屏幕保持黑色,因为在 jpegCallback 之后没有重新触发 startPreview()。堆栈跟踪对我来说毫无用处。 奇怪的是,这只发生在我的 Galaxy S 上,而不是模拟器上。我真的不知道如何继续:/ 任何人都知道什么可能有用吗?
10-28 18:59:40.649: ERROR/SecCamera(4291): SetRotate(angle(0)) 10-28 18:59:40.649: ERROR/CameraHardwareSec(4291): ====setParameters processingmethod = (null) 10-28 18:59:40.649: ERROR/SecCamera(4291): setRecordingSize(width(800), height(480)) 10-28 18:59:40.673: ERROR/SecCamera(4291): SetRotate(angle(0)) 10-28 18:59:40.673: ERROR/CameraHardwareSec(4291): ====setParameters processingmethod = (null) 10-28 18:59:40.673: ERROR/SecCamera(4291): setRecordingSize(width(800), height(480)) 10-28 18:59:40.692: ERROR/SecCamera(4291): SetRotate(angle(0)) 10-28 18:59:40.692: ERROR/CameraHardwareSec(4291): ====setParameters processingmethod = (null) 10-28 18:59:40.692: ERROR/SecCamera(4291): setRecordingSize(width(800), height(480)) 10-28 18:59:40.712: ERROR/SecCamera(4291): SetRotate(angle(0)) 10-28 18:59:40.712: ERROR/CameraHardwareSec(4291): ====setParameters processingmethod = (null) 10-28 18:59:40.712: ERROR/SecCamera(4291): setRecordingSize(width(800), height(480)) 10-28 18:59:40.751: ERROR/CameraHardwareSec(4291): stopPreview() 10-28 18:59:40.751: ERROR/SecCamera(4291): cancelAutofocus() 10-28 18:59:40.751: ERROR/SecCamera(4291): cancelAutofocus() end, 0, 4 10-28 18:59:40.768: ERROR/SecCamera(4291): stopPreview() 10-28 18:59:40.768: ERROR/SecCamera(4291): fimc_v4l2_streamoff() 10-28 18:59:40.797: ERROR/CameraHardwareSec(4291): stopPreview() end 10-28 18:59:41.622: ERROR/SecCamera(4291): fimc_v4l2_streamoff() 10-28 18:59:46.536: ERROR/dalvikvm(2993): Failed to write stack traces to /data/anr/traces.txt (2775 of 2970): Unknown error: 0 10-28 18:59:46.540: ERROR/dalvikvm(2919): Failed to write stack traces to /data/anr/traces.txt (-1 of 3414): Math result not representable 10-28 18:59:46.610: ERROR/dalvikvm(3044): Failed to write stack traces to /data/anr/traces.txt (3354 of 7154): Math result not representable ...
这是我的(缩短的)代码:
public class CameraActivity extends Activity implements MenuViewCallback, CutoutPathManagerCallback { public static final String TAG = "CutoutCamera"; Preview preview; OverlayView overlay; static MenuView menuView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Hide the window title. requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); ... preview = (Preview) this.findViewById(R.id.preview); ... } ... @Override protected void onResume() { super.onResume(); this.log("onResume()"); preview.openCamera(); } @Override protected void onPause() { super.onPause(); this.log("onPause()"); if (preview.camera != null) { preview.camera.release(); preview.camera = null; } } // Called when shutter is opened ShutterCallback shutterCallback = new ShutterCallback() { // public void onShutter() { Log.d(TAG, "onShutter'd"); } }; // Handles data for raw picture PictureCallback rawCallback = new PictureCallback() { // public void onPictureTaken(byte[] data, Camera camera) { Log.d(TAG, "onPictureTaken - raw"); } }; // Handles data for jpeg picture PictureCallback jpegCallback = new PictureCallback() { // public void onPictureTaken(byte[] data, Camera camera) { Log.d(TAG, "onPictureTaken - jpeg"); ... } }; @Override public void shootButtonClicked() { preview.camera.takePicture(shutterCallback, rawCallback, jpegCallback); } @Override public void focusButtonClicked() { preview.camera.autoFocus(new Camera.AutoFocusCallback() { public void onAutoFocus(boolean success, Camera camera) { } }); } }
/** * order of execution: * openCamera() * onMeasure() * onLayout() * onMeasure() * onLayout() * surfaceCreated() * surfaceChanged() * onMeasure() * onLayout() * onMeasure() * @author stephan * */ class Preview extends ViewGroup implements SurfaceHolder.Callback { // private static final String TAG = "Preview"; SurfaceHolder mHolder; // public Camera camera; // private List supportedPreviewSizes; private Size previewSize; SurfaceView mSurfaceView; CameraActivity cameraActivity; int l2 = 0, t2 = 0, r2 = 0, b2 = 0; int padding = 20; Size optimalPreviewSize, optimalPictureSize; // the size of this view. gets set in onMeasure() int fullWidth, fullHeight; public Preview(Context context) { super(context); init(context); } public Preview(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public Preview(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } private void init(Context context) { setKeepScreenOn(true); cameraActivity = (CameraActivity) context; mSurfaceView = new SurfaceView(context); addView(mSurfaceView); mHolder = mSurfaceView.getHolder(); // mHolder.addCallback(this); // mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); // } ... public void openCamera() { cameraActivity.log("openCamera()"); if (this.camera == null) { cameraActivity.log("Camera.open()"); this.camera = Camera.open(); //supportedPreviewSizes = camera.getParameters().getSupportedPreviewSizes(); requestLayout(); // -> onMeassure() -> onLayout() } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { cameraActivity.log("onMeasure()"); // We purposely disregard child measurements because act as a // wrapper to a SurfaceView that centers the camera preview instead // of stretching it. fullWidth = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec); fullHeight = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec); setMeasuredDimension(fullWidth, fullHeight); if(this.camera != null){ cameraActivity.log("fullSize:"+fullWidth+"x"+fullHeight); this.setCameraPreviewSize(); this.setCameraPictureSize(); } } private void calcScaledPreviewSize(){ ... } ... private void setCameraPreviewSize() { Camera.Parameters parameters = camera.getParameters(); if(parameters.getPreviewSize() != this.getOptimalPreviewSize()){ parameters.setPreviewSize(this.getOptimalPreviewSize().width, this.getOptimalPreviewSize().height); this.camera.setParameters(parameters); } } private void setCameraPictureSize() { Camera.Parameters parameters = this.camera.getParameters(); if(parameters.getPictureSize() != this.getOptimalCameraPictureSize()){ parameters.setPictureSize(getOptimalCameraPictureSize().width, getOptimalCameraPictureSize().height); this.camera.setParameters(parameters); } } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { cameraActivity.log("onLayout()"); if (changed && getChildCount() > 0 && this.camera != null) { final View child = getChildAt(0); cameraActivity.log("r:"+this.getPreviewRight()+" l:"+this.getPreviewLeft()+" b:"+this.getPreviewBottom()+" t:"+this.getPreviewTop()); child.layout(this.getPreviewLeft(), this.getPreviewTop(), this.getPreviewRight(), this.getPreviewBottom()); cameraActivity.initOverlay(this.getPreviewLeft(),this.getPreviewTop(),this.getPreviewRight(),this.getPreviewBottom()); } } private Size getOptimalPreviewSize() { if(optimalPreviewSize == null){ //calculate optimal preview size } return optimalPreviewSize; } private Size getOptimalCameraPictureSize() { if(optimalPictureSize == null){ //calculate optimal image size } return optimalPictureSize; } // Called once the holder is ready public void surfaceCreated(SurfaceHolder holder) { // // The Surface has been created, acquire the camera and tell it where // to draw. cameraActivity.log("surfaceCreated()"); try { if (this.camera != null) { this.camera.setPreviewDisplay(holder); } } catch (IOException exception) { Log.e(TAG, "IOException caused by setPreviewDisplay()", exception); } } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { cameraActivity.log("surfaceChanged()"); if (camera != null) { Camera.Parameters parameters = camera.getParameters(); parameters.setPreviewSize(getOptimalPreviewSize().width, getOptimalPreviewSize().height); requestLayout(); camera.setParameters(parameters); camera.startPreview(); } } public void surfaceDestroyed(SurfaceHolder holder) { // cameraActivity.log("surfaceDestroyed()"); if(this.camera != null){ camera.stopPreview(); } } public void releaseCamera(){ cameraActivity.log("releaseCamera()"); if (camera != null) { camera.stopPreview(); camera.setPreviewCallback(null); camera.release(); camera = null; } } }
I have some troubles with the onPause() onResume() camera live cycle:
Camera with preview, and taking photos works totally fine. With one exceptions:
I start the app, click the home button, switch back to the app and take another shot.
Result: shuttercallback is still executed (see code), but jpeg callback isn't anymore! Then my galaxy S vibrates, and the screen stays black, since startPreview() is not re-triggered after jpegCallback. The stack trace is far from usefull for me.
Strange thing is that this only happens on my Galaxy S, not on the emulator. I have really no clue how to move on :/
Anyone has an idea what could be usefull?
10-28 18:59:40.649: ERROR/SecCamera(4291): SetRotate(angle(0)) 10-28 18:59:40.649: ERROR/CameraHardwareSec(4291): ====setParameters processingmethod = (null) 10-28 18:59:40.649: ERROR/SecCamera(4291): setRecordingSize(width(800), height(480)) 10-28 18:59:40.673: ERROR/SecCamera(4291): SetRotate(angle(0)) 10-28 18:59:40.673: ERROR/CameraHardwareSec(4291): ====setParameters processingmethod = (null) 10-28 18:59:40.673: ERROR/SecCamera(4291): setRecordingSize(width(800), height(480)) 10-28 18:59:40.692: ERROR/SecCamera(4291): SetRotate(angle(0)) 10-28 18:59:40.692: ERROR/CameraHardwareSec(4291): ====setParameters processingmethod = (null) 10-28 18:59:40.692: ERROR/SecCamera(4291): setRecordingSize(width(800), height(480)) 10-28 18:59:40.712: ERROR/SecCamera(4291): SetRotate(angle(0)) 10-28 18:59:40.712: ERROR/CameraHardwareSec(4291): ====setParameters processingmethod = (null) 10-28 18:59:40.712: ERROR/SecCamera(4291): setRecordingSize(width(800), height(480)) 10-28 18:59:40.751: ERROR/CameraHardwareSec(4291): stopPreview() 10-28 18:59:40.751: ERROR/SecCamera(4291): cancelAutofocus() 10-28 18:59:40.751: ERROR/SecCamera(4291): cancelAutofocus() end, 0, 4 10-28 18:59:40.768: ERROR/SecCamera(4291): stopPreview() 10-28 18:59:40.768: ERROR/SecCamera(4291): fimc_v4l2_streamoff() 10-28 18:59:40.797: ERROR/CameraHardwareSec(4291): stopPreview() end 10-28 18:59:41.622: ERROR/SecCamera(4291): fimc_v4l2_streamoff() 10-28 18:59:46.536: ERROR/dalvikvm(2993): Failed to write stack traces to /data/anr/traces.txt (2775 of 2970): Unknown error: 0 10-28 18:59:46.540: ERROR/dalvikvm(2919): Failed to write stack traces to /data/anr/traces.txt (-1 of 3414): Math result not representable 10-28 18:59:46.610: ERROR/dalvikvm(3044): Failed to write stack traces to /data/anr/traces.txt (3354 of 7154): Math result not representable ...
Here is my (shortened) code:
public class CameraActivity extends Activity implements MenuViewCallback, CutoutPathManagerCallback { public static final String TAG = "CutoutCamera"; Preview preview; OverlayView overlay; static MenuView menuView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Hide the window title. requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); ... preview = (Preview) this.findViewById(R.id.preview); ... } ... @Override protected void onResume() { super.onResume(); this.log("onResume()"); preview.openCamera(); } @Override protected void onPause() { super.onPause(); this.log("onPause()"); if (preview.camera != null) { preview.camera.release(); preview.camera = null; } } // Called when shutter is opened ShutterCallback shutterCallback = new ShutterCallback() { // public void onShutter() { Log.d(TAG, "onShutter'd"); } }; // Handles data for raw picture PictureCallback rawCallback = new PictureCallback() { // public void onPictureTaken(byte[] data, Camera camera) { Log.d(TAG, "onPictureTaken - raw"); } }; // Handles data for jpeg picture PictureCallback jpegCallback = new PictureCallback() { // public void onPictureTaken(byte[] data, Camera camera) { Log.d(TAG, "onPictureTaken - jpeg"); ... } }; @Override public void shootButtonClicked() { preview.camera.takePicture(shutterCallback, rawCallback, jpegCallback); } @Override public void focusButtonClicked() { preview.camera.autoFocus(new Camera.AutoFocusCallback() { public void onAutoFocus(boolean success, Camera camera) { } }); } }
/** * order of execution: * openCamera() * onMeasure() * onLayout() * onMeasure() * onLayout() * surfaceCreated() * surfaceChanged() * onMeasure() * onLayout() * onMeasure() * @author stephan * */ class Preview extends ViewGroup implements SurfaceHolder.Callback { // private static final String TAG = "Preview"; SurfaceHolder mHolder; // public Camera camera; // private List supportedPreviewSizes; private Size previewSize; SurfaceView mSurfaceView; CameraActivity cameraActivity; int l2 = 0, t2 = 0, r2 = 0, b2 = 0; int padding = 20; Size optimalPreviewSize, optimalPictureSize; // the size of this view. gets set in onMeasure() int fullWidth, fullHeight; public Preview(Context context) { super(context); init(context); } public Preview(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public Preview(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } private void init(Context context) { setKeepScreenOn(true); cameraActivity = (CameraActivity) context; mSurfaceView = new SurfaceView(context); addView(mSurfaceView); mHolder = mSurfaceView.getHolder(); // mHolder.addCallback(this); // mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); // } ... public void openCamera() { cameraActivity.log("openCamera()"); if (this.camera == null) { cameraActivity.log("Camera.open()"); this.camera = Camera.open(); //supportedPreviewSizes = camera.getParameters().getSupportedPreviewSizes(); requestLayout(); // -> onMeassure() -> onLayout() } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { cameraActivity.log("onMeasure()"); // We purposely disregard child measurements because act as a // wrapper to a SurfaceView that centers the camera preview instead // of stretching it. fullWidth = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec); fullHeight = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec); setMeasuredDimension(fullWidth, fullHeight); if(this.camera != null){ cameraActivity.log("fullSize:"+fullWidth+"x"+fullHeight); this.setCameraPreviewSize(); this.setCameraPictureSize(); } } private void calcScaledPreviewSize(){ ... } ... private void setCameraPreviewSize() { Camera.Parameters parameters = camera.getParameters(); if(parameters.getPreviewSize() != this.getOptimalPreviewSize()){ parameters.setPreviewSize(this.getOptimalPreviewSize().width, this.getOptimalPreviewSize().height); this.camera.setParameters(parameters); } } private void setCameraPictureSize() { Camera.Parameters parameters = this.camera.getParameters(); if(parameters.getPictureSize() != this.getOptimalCameraPictureSize()){ parameters.setPictureSize(getOptimalCameraPictureSize().width, getOptimalCameraPictureSize().height); this.camera.setParameters(parameters); } } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { cameraActivity.log("onLayout()"); if (changed && getChildCount() > 0 && this.camera != null) { final View child = getChildAt(0); cameraActivity.log("r:"+this.getPreviewRight()+" l:"+this.getPreviewLeft()+" b:"+this.getPreviewBottom()+" t:"+this.getPreviewTop()); child.layout(this.getPreviewLeft(), this.getPreviewTop(), this.getPreviewRight(), this.getPreviewBottom()); cameraActivity.initOverlay(this.getPreviewLeft(),this.getPreviewTop(),this.getPreviewRight(),this.getPreviewBottom()); } } private Size getOptimalPreviewSize() { if(optimalPreviewSize == null){ //calculate optimal preview size } return optimalPreviewSize; } private Size getOptimalCameraPictureSize() { if(optimalPictureSize == null){ //calculate optimal image size } return optimalPictureSize; } // Called once the holder is ready public void surfaceCreated(SurfaceHolder holder) { // // The Surface has been created, acquire the camera and tell it where // to draw. cameraActivity.log("surfaceCreated()"); try { if (this.camera != null) { this.camera.setPreviewDisplay(holder); } } catch (IOException exception) { Log.e(TAG, "IOException caused by setPreviewDisplay()", exception); } } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { cameraActivity.log("surfaceChanged()"); if (camera != null) { Camera.Parameters parameters = camera.getParameters(); parameters.setPreviewSize(getOptimalPreviewSize().width, getOptimalPreviewSize().height); requestLayout(); camera.setParameters(parameters); camera.startPreview(); } } public void surfaceDestroyed(SurfaceHolder holder) { // cameraActivity.log("surfaceDestroyed()"); if(this.camera != null){ camera.stopPreview(); } } public void releaseCamera(){ cameraActivity.log("releaseCamera()"); if (camera != null) { camera.stopPreview(); camera.setPreviewCallback(null); camera.release(); camera = null; } } }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这就是我最终 100% 修复它的方法(适用于我尝试过的每台设备,包括 Galaxy S):
我在 Resume 上销毁了摄像头预览对象并重新实例化(就像在启动时一样)。更多详细信息请参见:
android:我没有得到堆栈跟踪,手机挂起
This is how I fixed it 100%, finally (working on every device I tried it on, including Galaxy S):
I destroyed the camere preview object onResume and reinstantiated all together (like on startup). More details here:
android: I get no stacktrace, phone just hangs
到达这篇文章有点晚了,但我也遇到了类似的问题。首先,如果你使用的是客户ROM,则可能是摄像头驱动程序的问题(我的一台X8运行4.0.4)。如果您按电源按钮将手机置于待机模式并在短时间内将其恢复(无论有或没有主屏幕锁定),该问题也存在。经过尝试和错误后,我发现在关闭相机后在 super.onPause 之前放置一个短暂的延迟是最好的。我的代码如下。
和 closeCamera();
It's a bit late to reach this post but i had the similar problem. First of all, if you using customer rom, it could be the problem of camera driver (mine one X8 runniing 4.0.4). The problem also exists if you press power button to put the phone in standby mode and bring it back in a short time (with or without home screen lock). After try and error i found that put a short delay after shut down camera before super.onPause is the best. My code as below.
and closeCamera();
我的猜测是,您所要做的就是在 Preview 中创建一个 setter 方法来重置相机(由于相机被释放,Preview 中的本地相机对象在 onPause() 之后变得无效,但 Preview 的其余状态仍然保持) 。
My guess is that all you have to do, is to create a setter method in Preview for resetting camera (the local camera object in Preview becomes invalid after onPause() since camera is released, but rest of the state of Preview is still maintained).