2012-03-12 17 views
9

Zbudowałem aplikację, która robi zdjęcia po dotknięciu podglądu. Mogę robić wiele zdjęć, ale czasami, gdy dotykam podglądu, aby zrobić zdjęcie, nie ma dźwięku migawki i cała aplikacja zatrzymuje się. Co więcej, jeśli spróbuję uruchomić uruchamianie wbudowanej aplikacji kamery, otrzymuję komunikat, że nie można użyć kamery.Aparat z Androidem - Czasami, gdy robię zdjęcia, aplikacja zawiesza się, a aparat nie nadaje się do użytku.

Nie znam przyczyny tego zachowania, dzieje się to przypadkowo, a kiedy to się dzieje, muszę ponownie uruchomić urządzenie (Samsung Galaxy S), aby móc ponownie korzystać z aparatu.

W DDM, po katastrofie widzę następujący wiersz: keyDispatchingTimedOut

Oto odpowiedni kod: CameraActivity Klasa:

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."); 

    } 
} 

Preview Klasa:

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

} 

Proszę o pomoc, próbuję kilka dni, aby zrozumieć, gdzie jest problem bez powodzenia

Eyal

+0

ktoś? Naprawdę utknąłem na tym – Eyal

+0

. Proponuję zapisać obrazek na karcie SD w wątku tła, a nie w głównym wątku UI. – Paul

Odpowiedz

6

Nie wiem, co powoduje, że błąd, że będzie naprawdę pomaga jeśli pisał wyjście loggcat od czasu od kiedy się ten błąd.

Ale, mogę zrobić kilka zgadywanek. Wygląda na to, że kamera jest zablokowana (wbudowany aparat nie działa). Jeśli twoja aplikacja jest zamknięta, blokada aparatu może być spowodowana błędem błędów w aparacie HAL aparatu Samsung. Zwłaszcza w starszych telefonach, takich jak Galaxy S, nie radziły sobie najlepiej z niewłaściwymi, a nie standardowymi połączeniami API.

Oto kilka wskazówek, co może być przyczyną takiego zachowania:

  1. należy dodać strażnika do robienia zdjęć. Teraz, jeśli dotkniesz ekranu i zrobisz zdjęcie, możesz ponownie dotknąć ekranu, zanim zdjęcie się skończy. Tak więc camera.takePicture() zostanie wywołane dwa razy. Drugi zawiedzie. To jest moje najlepsze przypuszczenie.

    Dodać trochę boolean isTakingPicture = false zmienną, a następnie:

    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. Czego korzystania previewCallback za? Nie robię tu niczego pożytecznego. Podgląd wywołań zwrotnych czasami może czasami powodować pewien ból, chociaż twój kod wygląda dobrze dla mnie. Możesz spróbować go usunąć i sprawdzić, czy to pomaga.

+0

Fantastyczne! Pierwsze rozwiązanie nie pomogło, ale drugie rozwiązanie (usunięcie previewCallback) rozwiązało problem. – Eyal

+0

Hmm, może wywołanie metody invalidate() na SurfaceView przypisanym do kamery jest problemem. Nigdy tego nie próbowałem i nie wyobrażam sobie, żeby to zrobił. Mimo wszystko uważam, że powinieneś również zastosować pierwsze rozwiązanie, aby zapobiec potencjalnym błędom. –

8

Właśnie napotykam ten problem podczas testowania mojej aplikacji na Samsung Galaxy SII. Po prostu trzeba usunąć podglądu zwrotnego przed wykonaniem zdjęcia:

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

W telefonie HTC Sensation, mojej niestandardowej aplikacji aparatu, wyświetlany jest podgląd na pełnym ekranie. Gdy użytkownik dotknie ekranu, wywoływana jest fokus. Gdy fokus jest zakończony i zakończy się sukcesem, zadzwonię do mCamera.takePicture. Czasami to działa, a ja otrzymuję wywołanie zwrotne do zapisywania danych JPG, innym razem pozostaje ono w takePicture, bez limitu czasu ani żadnych komunikatów debugowania. Jest to bardzo denerwujące, ponieważ trzeba ponownie uruchamiać telefon za każdym razem i nie wiedzieć, na czym polega problem. SettingsPreviewCallback to null nie pomoże. Jakieś inne pomysły? – radhoo

2

doświadczyłem podobnego problemu zgłoszone tutaj. Na LG p705 i Samsung Galaxy Trend, po zrobieniu zdjęcia, podgląd jest zamrożony i kamera przestała działać, dopóki telefon nie zostanie ponownie uruchomiony. Jednak na Galaxy S3 podgląd nadal wyświetla się poprawnie nawet po wielu fotokamerach.

Podczas debugowania zauważyłem, że klasa odpowiedniego słuchacza otrzymała więcej niż jedno połączenie, gdy przycisk aparatu został naciśnięty, aby wykonać zdjęcie. Nie jestem pewien, dlaczego jest wywoływany dwukrotnie, mimo że przycisk był tylko raz kliknięty. W każdym razie, dzięki sugestii Tomasza, aby użyć zmiennej boolowskiej, drugie połączenie pomija wykonanie zdjęcia podczas pierwszej próby. I dziękuję Eyalowi za to pytanie. :)

Powiązane problemy