android: Камера onPause / onResume проблема


У меня есть некоторые проблемы с onPause() onResume () камера live цикла: Камера с предварительным просмотром и съемкой фотографий работает абсолютно нормально. За одним исключением:

Я запускаю приложение, нажимаю кнопку home, переключаюсь обратно на приложение и делаю еще один снимок.

Результат: shuttercallback все еще выполняется (см. код), но обратного вызова jpeg больше нет! Затем мой galaxy S вибрирует, и экран остается черным, так как startPreview() не запускается повторно после jpegCallback. Трассировка стека далека от полезно для меня. Странно, что это происходит только на моем 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;
        }
    }
}

3 11

3 ответа:

Вот как я исправил его на 100%, наконец (работая на каждом устройстве, которое я пробовал, включая Galaxy S):

Я уничтожил объект camere preview onResume и восстановил все вместе (как при запуске). Подробнее здесь:

Android: я не получаю stacktrace, телефон просто висит

Это немного поздно, чтобы достичь этого поста, но у меня была аналогичная проблема. Прежде всего, если вы используете клиентский rom, это может быть проблема драйвера камеры (мой один X8 runniing 4.0.4). Проблема также возникает, если вы нажимаете кнопку питания, чтобы перевести телефон в режим ожидания и вернуть его в течение короткого времени (с или без блокировки главного экрана). После попытки и ошибки я обнаружил, что поставил короткую задержку после выключения камеры перед супер.метод 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();
  }

И closeCamera ();

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

Я думаю, что все, что вам нужно сделать, это создать метод setter в Preview для сброса камеры (локальный объект камеры в Preview становится недействительным после onPause (), так как камера освобождена, но остальная часть состояния предварительного просмотра все еще сохраняется).