9
votes

Appareil photo Android - Parfois, lorsque je prends des photos, l'application gèle et la caméra n'est pas utilisable

J'ai construit une application qui prend des photos lorsque vous touchez l'aperçu. Je peux prendre de nombreuses photos, mais parfois, lorsque je touche l'aperçu pour prendre une photo, il n'y a pas de son de déclenchement et toute l'application gèle. De plus, après cela, si j'essaie de lancer l'application de la caméra intégrée, je reçois un message que la caméra ne peut pas être utilisée.

Je ne connais pas la raison de ce comportement, cela se produit au hasard et quand Il arrive que je dois redémarrer l'appareil (Samsung Galaxy S) pour pouvoir utiliser à nouveau la caméra. P>

Dans le DDM, après le crash, je peux voir la ligne suivante: KeyDisPatchingTimeDout P>

Voici le code pertinent: CLASSIFITY CLASS: P>

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

}


1 commentaires

De plus, je suggère d'enregistrer une image sur une carte SD à effectuer dans un fil d'arrière-plan, pas le fil d'interface utilisateur principal.


3 Réponses :


6
votes

Je ne sais pas ce qui cause cet insecte, il serait Aide vraiment forte> si vous avez posté la sortie de loggcat à partir de l'heure à partir de laquelle cette erreur s'est produite.

Mais, je peux faire des gusesses. On dirait que la caméra est verrouillée (caméra intégrée ne fonctionne pas). Si votre application d'application est fermée, le verrouillage de la caméra peut être causé par une manipulation d'erreurs erroreus dans Samsung Camera Hal. Surtout dans les téléphones plus âgés, comme Galaxy S, ils n'ont pas fait le meilleur travail pour la manipulation erronée ou non des appels d'API standard. P>

Voici quelques suggestions de ce qui peut avoir causé ce comportement: P>

  • Vous devez ajouter un garde pour la prise d'image. En ce moment, si vous touchez l'écran et que vous prenez une photo, vous pouvez toucher l'écran à nouveau avant que la photo ne se termine. Donc, la caméra.takepicture () sera appelée deux fois. Le second échouera. C'est ma meilleure hypothèse. P>

    Ajouter quelques boolean isteakingpicture = false code> variable puis: p>

    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;
      ...
    
  • Qu'est-ce que vous utilisez PreviewCallback? Je ne fais rien d'utile ici. Les rappels d'aperçu peuvent parfois parfois causer de la douleur, bien que votre code vous ait fière allure. Vous pouvez alwys essayer de le supprimer et vérifier si cela aide. P> li> ol> p>


  • 2 commentaires

    Fantastique! La première solution n'a pas aidé, mais la deuxième solution (supprimer le previdageCallback) a résolu le problème


    HMM, peut-être appeler invalider () sur la supervision affectée à une caméra est le problème. Je n'ai jamais essayé cela et je ne peux imaginer que rien de prêt à le faire. Néanmoins, je pense que vous devriez également appliquer la première solution également pour prévenir les erreurs potentielles.



    8
    votes

    Je viens de courir dans ce numéro lorsque vous testez ma candidature sur un Samsung Galaxy SII. Il vous suffit de supprimer le rappel d'aperçu avant de prendre la photo:

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


    1 commentaires

    Sur une Sensation HTC, mon application de caméra personnalisée affiche l'aperçu de l'espace complet. Lorsque l'utilisateur tapote l'écran, la mise au point est appelée. Lorsque la mise au point est terminée et réussie, j'appelle mcamera.takepicture. Parfois, cela fonctionne et je reçois le rappel pour sauvegarder des données JPG, d'autres fois, il reste juste à la prise à prendre, sans délai ni messages de débogage. C'est tellement ennuyeux, après avoir redémarrer le téléphone à chaque fois, et ne pas savoir quel est le problème. ParamètresPréviewcallback to Null n'aide pas. Toute autre idée?



    2
    votes

    J'ai eu un problème similaire signalé ici. Sur LG P705 et Samsung Galaxy Trend, après avoir pris une photo, l'aperçu est congelé et la caméra n'était plus utilisable tant que le téléphone n'a pas été redémarré. Sur Galaxy S3 Toutefois, l'aperçu continue d'afficher correctement même après plusieurs claviers photo.

    Lors du débogage, j'ai remarqué que la classe d'écoute concernée recevait plus d'un appel lorsque le bouton de la caméra a été enfoncé pour prendre une photo. Je ne suis pas sûr de savoir pourquoi il est appelé deux fois, même si le bouton n'était qu'un clic une fois. En tout état de cause, grâce à la suggestion de Tomasz à utiliser une variable booléenne, le deuxième appel passe de photo en prenant une photo alors que la première tentative est en cours. Et merci à tails pour la question aussi. :)


    0 commentaires