Камера Android - Иногда, когда я делаю фотографии, приложение зависает, и камера не используется - PullRequest
9 голосов
/ 12 марта 2012

Я создал приложение, которое делает фотографии, когда вы касаетесь предварительного просмотра. Я могу сделать много фотографий, но иногда, когда я касаюсь предварительного просмотра, чтобы сделать фотографию, нет звука затвора, и все приложение зависает. Более того, после этого, если я пытаюсь запустить, запустить встроенное приложение камеры, я получаю сообщение, что камера не может быть использована.

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

В DDM после сбоя я вижу следующую строку: keyDispatchingTimedOut

Вот соответствующий код: CameraActivity Class:

public class CameraActivity extends Activity {
  private static final String TAG = "CameraDemo";
  Preview preview;

  public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    preview = new Preview(this);
    ((FrameLayout) findViewById(R.id.preview)).addView(preview);
    ((FrameLayout) findViewById(R.id.preview)).setOnTouchListener(preview); 

    Log.d(TAG, "Camera Activity Created.");

  }
}

Класс просмотра:

    class Preview extends SurfaceView implements SurfaceHolder.Callback, OnTouchListener {
    private static final String TAG = "Preview";

    SurfaceHolder mHolder;
    public Camera camera;
    Context ctx;
    boolean previewing = false;

    Preview(Context context) {
        super(context);
        ctx = context;
        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }


    // 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.
        camera = Camera.open();
    }

    // Called when the holder is destroyed
    public void surfaceDestroyed(SurfaceHolder holder) {

        if (camera != null) {
            camera.setPreviewCallback(null);
            camera.stopPreview();  
            camera.release();
            camera = null;
        }

        previewing = false;
    }

    // Called when holder has changed
    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {

        if(previewing){
             camera.stopPreview();
             previewing = false;
        }

        if (camera != null){
            try {

                camera.setDisplayOrientation(90);
                camera.setPreviewDisplay(holder);
                camera.setPreviewCallback(new PreviewCallback() {
                    // Called for each frame previewed
                    public void onPreviewFrame(byte[] data, Camera camera) {
                        Log.d(TAG, "onPreviewFrame called at: " + System.currentTimeMillis());  
                        Preview.this.invalidate();
                    }
                });
                camera.startPreview();
                previewing = true;
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    public boolean onTouch(View v, MotionEvent event) {
        camera.takePicture(shutterCallback, rawCallback, jpegCallback);
        return false;
    }


    // 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) {
            FileOutputStream outStream = null;
            try {
                // Write to SD Card
                outStream = new FileOutputStream(String.format("/sdcard/TVguide/Detection/detected.jpg", System.currentTimeMillis())); // <9>
                outStream.write(data);
                outStream.close();
                Log.d(TAG, "onPictureTaken - wrote bytes: " + data.length);
            } catch (FileNotFoundException e) { // <10>
                //Toast.makeText(ctx, "Exception #2", Toast.LENGTH_LONG).show();
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {}
            Log.d(TAG, "onPictureTaken - jpeg");
            Toast.makeText(ctx, "SAVED", Toast.LENGTH_SHORT).show();

            camera.startPreview();
        }
    };

}

Пожалуйста, помогите, я пытаюсь несколько дней понять, в чем проблема, но безуспешно

Эяль

Ответы [ 3 ]

8 голосов
/ 14 сентября 2012

Я только столкнулся с этой проблемой при тестировании своего приложения на Samsung Galaxy SII. Вы просто должны удалить обратный вызов предварительного просмотра, прежде чем делать снимок:

mCamera.setPreviewCallback(null);
mCamera.takePicture(null, null, mPictureCallback);
6 голосов
/ 15 марта 2012

Я не знаю, что является причиной этой ошибки, действительно поможет, если вы разместите вывод loggcat со времени, когда эта ошибка произошла.

Но я могу сделать несколько уловок. Похоже, камера заблокирована (встроенная камера не работает). Если приложение закрылось принудительно, блокировка камеры может быть вызвана ошибкой обработки ошибок в камере Samsung HAL. Особенно в старых телефонах, таких как Galaxy S, они не справлялись с ошибками или не справлялись со стандартными вызовами API.

Вот несколько советов о том, что могло вызвать такое поведение:

  1. Вы должны добавить охрану для фотографирования. Прямо сейчас, если вы дотронетесь до экрана и сделаете снимок, вы можете снова коснуться экрана, прежде чем снимок закончится. Таким образом, camera.takePicture () будет вызван дважды. Второй провалится. Это мое лучшее предположение.

    Добавьте переменную boolean isTakingPicture = false, а затем:

    public boolean onTouch(View v, MotionEvent event) {
      if (!isTakingPicture) {
        camera.takePicture(shutterCallback, rawCallback, jpegCallback);
        isTakingPicture = true;
      }
      return false;
    }
    ...
    public void onPictureTaken(byte[] data, Camera camera) {
      isTakingPicture = false;
      ...
    
  2. Для чего вы используете PreviewCallback? Я не делаю ничего полезного здесь. Предварительные обратные вызовы иногда могут вызывать некоторые проблемы, хотя ваш код выглядит хорошо для меня. Вы также можете попытаться удалить его и проверить, помогает ли это.

2 голосов
/ 24 января 2014

Я столкнулся с подобной проблемой, о которой сообщалось здесь. На LG p705 и Samsung Galaxy Trend после фотосъемки предварительный просмотр завис, и камера перестала использоваться до перезагрузки телефона. Однако на Galaxy S3 предварительный просмотр продолжает отображаться правильно даже после нескольких фотоснимков.

Во время отладки я заметил, что соответствующий класс слушателей получал более одного вызова при нажатии кнопки камеры для съемки. Я не уверен, почему он вызывается дважды, хотя кнопка была нажата только один раз. В любом случае, благодаря предложению Томаша использовать логическую переменную, второй вызов пропускает фотографирование во время первой попытки. И спасибо Эялю за этот вопрос. :)

...