59 votes

Méthode appelée après l'exception release() incapable de reprendre avec la caméra android

En développant une application caméra, j'ai rencontré une exception qui se produisait uniquement lorsque je passais à une autre application (onPause() pour mon application).

01-15 17:22:15.017: E/AndroidRuntime(14336): FATAL EXCEPTION: main
01-15 17:22:15.017: E/AndroidRuntime(14336): java.lang.RuntimeException: Méthode appelée après la libération()
01-15 17:22:15.017: E/AndroidRuntime(14336):    at android.hardware.Camera.setPreviewDisplay(Native Method)
01-15 17:22:15.017: E/AndroidRuntime(14336):    at android.hardware.Camera.setPreviewDisplay(Camera.java:357)
01-15 17:22:15.017: E/AndroidRuntime(14336):    at com.sora.cbir.yuki.image.leaf.CameraPreview.surfaceCreated(CameraPreview.java:32)
01-15 17:22:15.017: E/AndroidRuntime(14336):    at android.view.SurfaceView.updateWindow(SurfaceView.java:551)
01-15 17:22:15.017: E/AndroidRuntime(14336):    at android.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.java:213)
01-15 17:22:15.017: E/AndroidRuntime(14336):    at android.view.View.dispatchWindowVisibilityChanged(View.java:4075)
01-15 17:22:15.017: E/AndroidRuntime(14336):    at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:742)
01-15 17:22:15.017: E/AndroidRuntime(14336):    at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:742)
01-15 17:22:15.017: E/AndroidRuntime(14336):    at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:742)
01-15 17:22:15.017: E/AndroidRuntime(14336):    at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:742)
01-15 17:22:15.017: E/AndroidRuntime(14336):    at android.view.ViewRoot.performTraversals(ViewRoot.java:858)
01-15 17:22:15.017: E/AndroidRuntime(14336):    at android.view.ViewRoot.handleMessage(ViewRoot.java:1995)
01-15 17:22:15.017: E/AndroidRuntime(14336):    at android.os.Handler.dispatchMessage(Handler.java:99)
01-15 17:22:15.017: E/AndroidRuntime(14336):    at android.os.Looper.loop(Looper.java:150)
01-15 17:22:15.017: E/AndroidRuntime(14336):    at android.app.ActivityThread.main(ActivityThread.java:4389)
01-15 17:22:15.017: E/AndroidRuntime(14336):    at java.lang.reflect.Method.invokeNative(Native Method)
01-15 17:22:15.017: E/AndroidRuntime(14336):    at java.lang.reflect.Method.invoke(Method.java:507)
01-15 17:22:15.017: E/AndroidRuntime(14336):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:849)
01-15 17:22:15.017: E/AndroidRuntime(14336):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:607)
01-15 17:22:15.017: E/AndroidRuntime(14336):    at dalvik.system.NativeStart.main(Native Method)

J'ai fait des recherches et j'ai découvert que je devais ajouter

mCamera.setPreviewCallback(null);

comme solution de contournement pour la pile caméra Android

Maintenant, mon onPause() ressemble à ceci :

@Override
protected void onPause() {
    super.onPause();
    try
    {    
        // release the camera immediately on pause event   
        //releaseCamera();
         mCamera.stopPreview(); 
         mCamera.setPreviewCallback(null);
         mCamera.release();
         mCamera = null;

    }
    catch(Exception e)
    {
        e.printStackTrace();
    }
}

et mon onResume() :

@Override
protected void onResume()
{
    super.onResume();
    try
    {
        mCamera.setPreviewCallback(null);
        mCamera = getCameraInstance();
        //mCamera.setPreviewCallback(null);
        mPreview = new CameraPreview(Imageupload.this, mCamera);//set preview
        preview.addView(mPreview);
    } catch (Exception e){
        Log.d(TAG, "Erreur lors du démarrage de l'aperçu de la caméra: " + e.getMessage());
    }
}   
}

et enfin ma méthode getCameraInstance() :

public Camera getCameraInstance(){
    Camera camera = null;
    try {
        camera = Camera.open(); // tentative pour obtenir une instance de la caméra
    }
    catch (Exception e){
        // La caméra n'est pas disponible (utilisée ou n'existe pas)
    }
    Camera.Parameters parameters = camera.getParameters();
    //mPreviewSize = getBestPreviewSize(parameters, wt, ht);
    //mPictureSize = getBestPictureSize(parameters, wt, ht);
    //Décalage W & H => si la caméra tourne de 90 degrés

    mPreviewSize = getOptimalPreviewSize(parameters, wt, ht); //original => wt,ht
    mPictureSize = getOptimalPictureSize(parameters, wt, ht); //original => wt,ht

    Log.d("CAMERA", "RÉSOLUTION DE L'ÉCRAN H: "+ht);
    Log.d("CAMERA", "RÉSOLUTION DE L'ÉCRAN W: "+wt);

    Log.d("CAMERA", "RÉSOLUTION DE L'APERÇU H: "+mPreviewSize.height);
    Log.d("CAMERA", "RÉSOLUTION DE L'APERÇU W: "+mPreviewSize.width);

    Log.d("CAMERA", "RÉSOLUTION DE L'IMAGE H: "+mPictureSize.height);
    Log.d("CAMERA", "RÉSOLUTION DE L'IMAGE W: "+mPictureSize.width);
    //définir la taille de l'aperçu en fonction de l'écran de l'appareil
    parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
    //définir la taille de l'image en fonction de l'écran de l'appareil
    parameters.setPictureSize(mPictureSize.width, mPictureSize.height);
    //définir le mode de sortie de la caméra
    parameters.setPictureFormat(PixelFormat.JPEG);
    //définir le mode de mise au point
    parameters.setFocusMode(FOCUS_MODE_AUTO);
    //définir le mode flash
    parameters.setFlashMode("auto");
    List fps = parameters.getSupportedPreviewFpsRange();
    //System.out.println("FPS size: " +fps.size());
    //System.out.println("MAX FPS:"+(fps.get(fps.size()-1)[1])/1000);
    //journal des fps min et max pris en charge par la caméra
    Log.d("CAMERA", "CAMERA MAX FPS: "+(fps.get(fps.size()-1)[1])/1000);
    Log.d("CAMERA", "CAMERA MIN FPS: "+(fps.get(fps.size()-1)[0])/1000);
    if(camera_fps)
    {
        parameters.setPreviewFpsRange(fps.get(fps.size()-1)[1], fps.get(fps.size()-1)[1]);
    }
    //définir les paramètres de la caméra
    camera.setParameters(parameters);

    Toast.makeText(getApplicationContext(), "Votre appareil est capable de prévisualiser @" + fps.get(fps.size()-1)[1]/1000+"fps!",Toast.LENGTH_SHORT).show();
    return camera; // retourne null si la caméra n'est pas disponible
}

Des idées sur comment résoudre cela?

145voto

ookami.kb Points 1071

J'ai le même problème. mCamera.setPreviewCallback(null); n'a pas aidé. Dans mon activité, j'ai ajouté ceci à releaseCamera:

mPreview.getHolder().removeCallback(mPreview);

et maintenant ça marche.

20voto

Neonigma Points 186

@La solution de @ookami.kb a également fonctionné pour moi, tout comme @srunni l'a commenté.

public void onPause() {
    super.onPause();

    if (mCamera != null) {
        mCamera.setPreviewCallback(null);
        mPreview.getHolder().removeCallback(mPreview);
        mCamera.release();
    }
}

J'ai également supprimé la méthode onDestroy.

10voto

Peter Knego Points 57985

Les documents indiquent clairement que camera.release() libère toutes les ressources de la caméra. Après cet appel, la référence de la caméra ne peut plus être utilisée.

Si vous souhaitez réutiliser la caméra, vous devez l'acquérir à nouveau via la méthode open(int).

Tout est décrit dans la documentation de la caméra.

5voto

Richa Points 31

Pour reprendre correctement, vous devez faire ceci :

@Override
public void onResume() {
    super.onResume();  

    // Obtenez l'instance de la caméra lorsque l'activité obtient pleinement le focus de l'utilisateur
    if (mCamera == null) {
        initializeCamera(); // Méthode locale pour gérer l'initialisation de la caméra
    }
}

protected void initializeCamera(){
    // Obtenez une instance de l'objet Caméra
    mCamera = getCameraInstance();

   // créez une classe de prévisualisation de base de la caméra qui peut être incluse dans une mise en page View.
    mPreview=new CameraPreview(this,mCamera);

    // ajoutez votre classe de prévisualisation à l'élément FrameLayout.
    preview.addView(mPreview);

   // Déclenchez la capture d'une image en appelant la méthode Camera.takePicture().
    captureButton.setOnClickListener(
            new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // obtenez une image de la caméra
                    mCamera.takePicture(null, null, mPicture);
                }
            }
        );
}

Et aussi juste pour rappeler que dans oncreate() ne faites rien sauf définir FrameLayout preview et Button captureButton.

2voto

Bala Points 21
@Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) {

    this.getHolder().removeCallback(this);
    mCamera.stopPreview();
    mCamera.release();
    mCamera = null;
    Log.e("surfaceDestroyed", "surfaceDestroyed");

}

Et réinitialiser la caméra dans la fonction onResume.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X