2012-03-12 3 views
9

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

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

В DDM, после аварии я могу увидеть следующую строку: keyDispatchingTimedOut

Вот соответствующий код: CameraActivity Класс:

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(); 
     } 
    }; 

} 

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

Эяль

+0

Кто-нибудь? Я действительно застрял – Eyal

+0

также я предлагаю сохранить изображение на SD-карту, которая будет сделана в фоновом потоке, а не в главном потоке пользовательского интерфейса. – Paul

ответ

6

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

Но, я могу сделать некоторые gusesses. Похоже, камера заблокирована (встроенная камера не работает). Если ваше приложение закрывается, блокировка камеры может быть вызвана ошибкой обработки ошибок в 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? Здесь я ничего полезного не делаю. Предварительный просмотр обратных вызовов иногда иногда вызывает некоторую боль, хотя ваш код выглядит хорошо для меня. Вы можете попытаться удалить его и проверить, помогает ли это.

+0

Фантастический! Первое решение не помогло, но второе решение (удаление previewCallback) решило проблему – Eyal

+0

Хм, возможно, вызов invalidate() на SurfaceView, назначенный для камеры, является проблемой. Я никогда не пробовал этого, и я не могу представить, чтобы он сделал это. Тем не менее, я думаю, вы также должны применить первое решение, чтобы предотвратить возможные ошибки. –

8

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

mCamera.setPreviewCallback(null); 
mCamera.takePicture(null, null, mPictureCallback); 
+1

На HTC Sensation, мое пользовательское приложение для камеры, показывает предварительный просмотр на весь экран. Когда пользователь удаляет экран, вызывается фокус. Когда фокус завершен и успешный, я вызываю mCamera.takePicture. Иногда это работает, и я получаю обратный вызов для сохранения JPG-данных, в других случаях он просто остается в takePicture, без тайм-аута и отладочных сообщений. Это так раздражает, когда приходится каждый раз перезапускать телефон, и не зная, в чем проблема. НастройкиPreviewCallback для null не помогают. Любые другие идеи? – radhoo

2

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

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

Смежные вопросы