安卓:相机在onPause/onResume时出现问题

12

我在onPause()和onResume()相机生命周期的处理上遇到了一些问题:

使用预览的相机以及拍照功能都可以正常工作。但有一个例外:

当我启动应用程序,点击主屏幕键,切换回应用程序并再次拍摄时,会发生某些问题。

结果:快门回调仍然被执行(请参见代码),但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);
// 隐藏窗口标题。 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; } }
// 当快门打开时调用 ShutterCallback shutterCallback = new ShutterCallback() { // public void onShutter() { Log.d(TAG, "onShutter'd"); } };
// 处理原始图片数据 PictureCallback rawCallback = new PictureCallback() { // public void onPictureTaken(byte[] data, Camera camera) { Log.d(TAG, "onPictureTaken - raw"); } };
// 处理JPEG格式图片数据 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) {
} }); } }
/** * 执行顺序: * openCamera() * onMeasure() * onLayout() * onMeasure() * onLayout() * surfaceCreated() * surfaceChanged() * onMeasure() * onLayout() * onMeasure() * */ 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; // 此视图的大小。在 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()");
// 我们故意忽略子视图的测量,因为它作为一个包装器, // 将相机预览居中而不是拉伸它。 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 setCameraPreview
3个回答

6

这是我最终解决问题的方法(在所有测试的设备上都有效,包括Galaxy S):

我在onResume中销毁了相机预览对象,并重新实例化它们(就像在启动时一样)。更多详情请点击以下链接:

android: I get no stacktrace, phone just hangs


这非常有帮助。尽管我们进行了管理编程,但应该鼓励清除有问题的东西。 - Vijay Kumar Kanta

4

虽然有些晚了,但我也遇到了类似的问题。首先,如果您使用的是自定义ROM,则可能是相机驱动程序的问题(我的One X8运行着4.0.4)。如果您按下电源按钮将手机置于待机模式,并在短时间内将其恢复(带或不带主屏幕锁定),该问题也存在。经过尝试和错误,我发现在 super.onPause 之前关闭相机并延迟一段时间是最好的解决方法。我的代码如下。

  @Override
  public void onPause() {
      // Log.d(TAG,"ccp_onPause");
      closeCamera();
      try {
          Thread.sleep(500);
      } catch (InterruptedException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
      }
      super.onPause();
  }

并关闭相机();

   public void closeCamera() {
      if (mCamera != null) {
          mCamera.stopPreview();
          mCamera.setPreviewCallback(null);
          mCamera.lock();
          mCamera.release();
          mCamera=null;
          requestLayout();
        }
    }

2

我的猜测是,你只需要在“预览”中创建一个设置器方法来重置相机(在onPause()之后,本地相机对象将变为无效,因为相机被释放,但是“预览”的其余状态仍然保持不变)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接