web-dev-qa-db-fra.com

java.lang.RuntimeException: échec de takePicture

lorsque je clique en continu sur le bouton Capture (sans interruption), obtenant une exception d'exécution, comment puis-je résoudre ce problème?

si ce n'est pas possible, comment puis-je gérer cette exception?

btnCapture = (ImageButton) findViewById(R.id.btnCapture);
                final MediaPlayer mp = MediaPlayer.create(CameraLauncherActivity.this, R.raw.button);
                btnCapture.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {

                            // line where getting RuntimeException
                        camera.takePicture(null, null, mPicture);   

                    }
                });

Journal:

02-12 14:48:41.580: E/AndroidRuntime(6997): FATAL EXCEPTION: main
02-12 14:48:41.580: E/AndroidRuntime(6997): Java.lang.RuntimeException: takePicture failed
02-12 14:48:41.580: E/AndroidRuntime(6997):     at Android.hardware.Camera.native_takePicture(Native Method)
02-12 14:48:41.580: E/AndroidRuntime(6997):     at Android.hardware.Camera.takePicture(Camera.Java:1126)
02-12 14:48:41.580: E/AndroidRuntime(6997):     at Android.hardware.Camera.takePicture(Camera.Java:1071)
02-12 14:48:41.580: E/AndroidRuntime(6997):     at app.cam.shane.CameraLauncherActivity$3.onClick(CameraLauncherActivity.Java:116)
02-12 14:48:41.580: E/AndroidRuntime(6997):     at Android.view.View.performClick(View.Java:4223)
02-12 14:48:41.580: E/AndroidRuntime(6997):     at Android.view.View$PerformClick.run(View.Java:17275)
02-12 14:48:41.580: E/AndroidRuntime(6997):     at Android.os.Handler.handleCallback(Handler.Java:615)
02-12 14:48:41.580: E/AndroidRuntime(6997):     at Android.os.Handler.dispatchMessage(Handler.Java:92)
02-12 14:48:41.580: E/AndroidRuntime(6997):     at Android.os.Looper.loop(Looper.Java:137)
02-12 14:48:41.580: E/AndroidRuntime(6997):     at Android.app.ActivityThread.main(ActivityThread.Java:4921)
02-12 14:48:41.580: E/AndroidRuntime(6997):     at Java.lang.reflect.Method.invokeNative(Native Method)
02-12 14:48:41.580: E/AndroidRuntime(6997):     at Java.lang.reflect.Method.invoke(Method.Java:511)
02-12 14:48:41.580: E/AndroidRuntime(6997):     at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:1036)
02-12 14:48:41.580: E/AndroidRuntime(6997):     at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:803)
02-12 14:48:41.580: E/AndroidRuntime(6997):     at dalvik.system.NativeStart.main(Native Method)

Remarque: - Comme dans Pudding Camera, ils permettent à l'utilisateur d'appuyer en continu sur le bouton Capture, mais ils ne montreront jamais d'exception, si vous faites 50 clics, il en capturera 10 ou plus d'images, chaque image après une heure spécifique mais ne montrant pas d'exception, comme je reçois dans mon code, de la même manière comment puis-je gérer cette exception?

Code complet:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_camera);

    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

            preview=(SurfaceView)findViewById(R.id.surface);     
            previewHolder=preview.getHolder();    
            previewHolder.addCallback(surfaceCallback);    
            previewHolder.setType(SurfaceHolder.SURFACE_TYPE_Push_BUFFERS);

            btnCapture = (ImageButton) findViewById(R.id.btnCapture);
            final MediaPlayer mp = MediaPlayer.create(CameraLauncherActivity.this, R.raw.button);
            btnCapture.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mp.start();
                    camera.takePicture(null, null, mPicture);                 
                }
            });


    @Override
    public void onResume() {  
        super.onResume();   
        camera=Camera.open(); 
    }  

    @Override   
    public void onPause() {  
        super.onPause();  
        if (inPreview) {  
        camera.stopPreview();   
        }   
        camera.release();   
        camera=null;   
        inPreview=false;         
    }   


    private Camera.Size getBestPreviewSize(int width, int height,
            Camera.Parameters parameters) {
            Camera.Size result=null;

            for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
                if (size.width <= width && size.height <= height) {
                    if (result == null) {
                        result=size;
                    }
                    else {
                        int resultArea=result.width * result.height;
                        int newArea=size.width * size.height;

                        if (newArea > resultArea) {
                            result=size;
                        }
                    }
                }
            }

            return(result);
        }

    private Camera.Size getSmallestPictureSize(Camera.Parameters parameters) {
        Camera.Size result=null;

        for (Camera.Size size : parameters.getSupportedPictureSizes()) {
            if (result == null) {
                result=size;
            }
            else {
                int resultArea=result.width * result.height;
                int newArea=size.width * size.height;

                if (newArea < resultArea) {
                    result=size;
                }
            }
        }

        return(result);
    }


    SurfaceHolder.Callback surfaceCallback=new SurfaceHolder.Callback(){

    public void surfaceCreated(SurfaceHolder holder) {     
        try {        
            camera.setPreviewDisplay(previewHolder); 
            }   catch (Throwable t) {   
                Log.e("PreviewDemo-surfaceCallback",
                        "Exception in setPreviewDisplay()", t);
                Toast.makeText(CameraLauncherActivity.this, t.getMessage(), Toast.LENGTH_LONG).show();       
                }     
            }      

    public void surfaceChanged(SurfaceHolder holder,int format, int width,int height) {
        params = camera.getParameters();       
        params.setFlashMode(Camera.Parameters.FLASH_MODE_ON);
        Camera.Size size = getBestPreviewSize(width, height, params);  
        Camera.Size pictureSize=getSmallestPictureSize(params);
        if (size != null && pictureSize != null) {      
            params.setPreviewSize(size.width, size.height);
            params.setPictureSize(pictureSize.width,
                    pictureSize.height);
            camera.setParameters(params);       
            camera.startPreview();       
            inPreview=true;                 

            }     
        }      

    public void surfaceDestroyed(SurfaceHolder holder) {

        }   
    };       

    PictureCallback mPicture = new PictureCallback() {
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {
            pictureFile = getOutputMediaFile();
            camera.startPreview();
            if (pictureFile == null) {
                return;
            }
            try {
                FileOutputStream fos = new FileOutputStream(pictureFile);
                fos.write(data);
                fos.close();
            } catch (FileNotFoundException e) {

            } catch (IOException e) {
            }
        }
    };

    static File getOutputMediaFile() {

        /* yyyy-MM-dd'T'HH:mm:ss.SSSZ */
        timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
        .format(new Date());

        // file name
        mediaFile = new File(LoginActivity.mediaStorageDir.getPath() + File.separator
                + "IMG_" + timeStamp + ".jpg");

        return mediaFile;

    }


}
41
Sun

Tout d'abord, interceptez vos exceptions dans onPictureTaken, laisser des sections de capture vides n'est pas une bonne pratique. Ensuite, j'ajouterais un indicateur qui empêcherait d'appeler takePicture () pendant l'enregistrement de l'image précédente. Plus tard dans votre bouton onClick, vous vérifieriez s'il est correct d'appeler takePicture ().

  1. Déclarez un drapeau en tant que membre de votre activité:

    private boolean safeToTakePicture = false;
    
  2. Dans surfaceChanged(), définissez simplement le drapeau sur true après avoir appelé startPreview ():

    camera.startPreview();
    safeToTakePicture = true;
    
  3. Dans votre écouteur onClick() vérifiez le drapeau et prenez la photo si vous le souhaitez:

    if (safeToTakePicture) {
        mp.start();
        camera.takePicture(null, null, mPicture); 
        safeToTakePicture = false;
    }
    
  4. Dans onPictureTaken(), définissez à nouveau le drapeau sur vrai après que l'image a été enregistrée (et ajoutez l'impression d'exception):

    PictureCallback mPicture = new PictureCallback() {
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {
            pictureFile = getOutputMediaFile();
            camera.startPreview();
    
            if (pictureFile == null) {
                //no path to picture, return
                safeToTakePicture = true;
                return;
            }
            try {
                FileOutputStream fos = new FileOutputStream(pictureFile);
                fos.write(data);
                fos.close();
    
            } catch (FileNotFoundException e) {
                e.printStackTrace();              //<-------- show exception
            } catch (IOException e) {
                e.printStackTrace();              //<-------- show exception
            }
    
            //finished saving picture 
            safeToTakePicture = true;
        }
    };
    

NOTES: Comme le disent les docs, "L'aperçu doit être démarré avant de pouvoir prendre une photo.", donc l'amélioration possible serait d'utiliser setPreviewCallback () pour enregistrer le rappel qui sera être appelé lorsque les données de prévisualisation sont disponibles et définir l'indicateur sur true lorsque onPreviewFrame est appelé.

63
Melquiades

J'ai également eu le même problème. plus tard, j'ai trouvé que startPreview est très important.

_camera.startPreview() est très important avant la vérification de takePicutre aux points 5 et 6 dans ce lien .

8
Make it Simple

Il peut y avoir plusieurs raisons à cela dans mon cas, j'essayais de prendre une photo sans prévisualisation (photo cachée) et j'utilisais SurfaceView, donc je l'ai remplacée par SurfaceTexture

SurfaceTexture surfaceTexture = new SurfaceTexture(10);
camera.setPreviewTexture(surfaceTexture);

et le problème a été résolu ... P.S J'obtenais cette erreur uniquement sur les appareils ci-dessus 6.0

4
Tabish

Avez-vous oublié d'appeler startPreview() sur l'appareil photo?

Voir ici pour plus d'informations.

2
ThaMe90

Cette méthode vous aidera à résoudre le problème.

private void safeCameraOpen(int id) {

        try {
            releaseCameraAndPreview();
            mCamera = Camera.open(id);
        } catch (Exception e) {
            Log.e(getString(R.string.app_name), "failed to open Camera");
            e.printStackTrace();
        }

    }

private void releaseCameraAndPreview() {
        if (mCamera != null) {
            mCamera.release();
            mCamera = null;
        }
    }
0
Ahmad Arslan