web-dev-qa-db-fra.com

méthode appelée après l'exception release () impossible de reprendre avec Android camera

Lors du développement d'une application d'appareil photo, j'ai rencontré une exception qui ne s'est produite que lorsque je suis passé à 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: Method called after release()
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 de caméras d'Android

ma onPause() ressemble maintenant à 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 ma 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, "Error starting camera preview: " + e.getMessage());
    }
}   
}

et enfin ma méthode getCameraInstance():

public Camera getCameraInstance(){
    Camera camera = null;
    try {
        camera = Camera.open(); // attempt to get a Camera instance
    }
    catch (Exception e){
        // Camera is not available (in use or does not exist)
    }
    Camera.Parameters parameters = camera.getParameters();
    //mPreviewSize = getBestPreviewSize(parameters, wt, ht);
    //mPictureSize = getBestPictureSize(parameters, wt, ht);
    //Shift W & H => if camera rotates 90 deg

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

    Log.d("CAMERA", "SCREEN RESOLUTION H: "+ht);
    Log.d("CAMERA", "SCREEN RESOLUTION W: "+wt);

    Log.d("CAMERA", "PREVIEW RESOLUTION H: "+mPreviewSize.height);
    Log.d("CAMERA", "PREVIEW RESOLUTION W: "+mPreviewSize.width);

    Log.d("CAMERA", "PICTURE RESOLUTION H: "+mPictureSize.height);
    Log.d("CAMERA", "PICTURE RESOLUTION W: "+mPictureSize.width);
    //set preview size based on device screen
    parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
    //set picture size based on device screen
    parameters.setPictureSize(mPictureSize.width, mPictureSize.height);
    //set output camera mode
    parameters.setPictureFormat(PixelFormat.JPEG);
    //set focous mode
    parameters.setFocusMode(FOCUS_MODE_AUTO);
    //set flash mode
    parameters.setFlashMode("auto");
    List<int[]> fps = parameters.getSupportedPreviewFpsRange();
    //System.out.println("FPS size: " +fps.size());
    //System.out.println("MAX FPS:"+(fps.get(fps.size()-1)[1])/1000);
    //log min and max camera supported fps
    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]);
    }
    //set camera parameters
    camera.setParameters(parameters);

    Toast.makeText(getApplicationContext(), "Your device are capable of previewing @" + fps.get(fps.size()-1)[1]/1000+"fps!",Toast.LENGTH_SHORT).show();
    return camera; // returns null if camera is unavailable
}

des idées pour résoudre le problème?

59
tom91136

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 ça marche maintenant.

144
ookami.kb

La solution @ ookami.kb a également fonctionné pour moi, ainsi que @srunni 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.

20
Neonigma

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 l'appareil photo, vous devez l'acquérir via une méthode open(int).

Tout est décrit dans les camera docs .

10
Peter Knego

Pour reprendre correctement, vous devez procéder comme suit:

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

    // Get the Camera instance as the activity achieves full user focus
    if (mCamera == null) {
        initializeCamera(); // Local method to handle camera initialization
    }
}



protected void initializeCamera(){
    // Get an instance of Camera Object
    mCamera = getCameraInstance();

   // create a basic camera preview class that can be included in a View layout.
    mPreview=new CameraPreview(this,mCamera);

    //add your preview class to the FrameLayout element.
    preview.addView(mPreview);

   //Trigger capturing an image by calling the Camera.takePicture() method.
    captureButton.setOnClickListener(
            new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // get an image from the camera
                    mCamera.takePicture(null, null, mPicture);
                }
            }
        );
}

Et aussi juste pour rappeler que dans oncreate () ne rien faire sauf définir l'aperçu FrameLayout et Button captureButton.

5
Richa
@Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) {

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

}

Et réinitialisez la caméra dans la fonction Reprise.

2
Bala

J'ai mis

mPreview.getHolder().removeCallback(mPreview);  

entre.

mCamera.setPreviewCallback(null);

et

mCamera.release();

et cela a fonctionné pour moi.

 @Override
            protected void onPause() {
                super.onPause();

                this.saveTextEdits();
                try {
                    mCamera.stopPreview();
                    mCamera.setPreviewCallback(null);
                    **mPreview.getHolder().removeCallback(mPreview);**
                    mCamera.release();
                    mCamera = null;
                }catch (Exception e){

                }
            }
1
radhason power

Ajout à la réponse d'Okambi.

C'est la fonction qui gâche tout lorsque vous reprenez:

 public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }

L'essai {} n'attrape pas l'exception levée. À savoir que mCamera n'existe pas, puis lorsqu'il essaie d'appeler setPreviewDisplay (holder), il y a un crash.

Donc, en supprimant le rappel, cette surfaceCreated n'est pas appelée et évite le plantage.

Ceci est TRÈS MAUVAIS DOCUMENTÉ par Google.

1
Aggressor

Si tu as:

Tentative d'appeler la méthode virtuelle 'void Android.hardware.Camera.setPreviewCallback (Android.hardware.Camera $ PreviewCallback)' sur une référence d'objet null

Je suis d'accord avec @ ookami.kb - mCamera.setPreviewCallback(null); ne suffit pas, derrière cela ajoutez également ceci:

mCameraView.getHolder().removeCallback(mCameraView);
0

J'ai rencontré le même problème, je l'ai résolu en - Ajoutant mCamera = null; dans surfaceDestroyed (support SurfaceHolder) méthode de Aperç classe.

public void surfaceDestroyed(SurfaceHolder holder) {
    // Surface will be destroyed when we return, so stop the preview.
    if (mCamera != null) {
        mCamera.stopPreview();
        mCamera.release();
        mCamera = null;
    }
}

et - Ajout

camera = Camera.open();
    camera.startPreview();
    params = camera.getParameters();
    preview.setCamera(camera);

dans OnResume () méthode de ma CameraActivity.

0
Rahul Sharma