java.lang.RuntimeException: ошибка takePicture

когда я постоянно нажимаю кнопку «Захват» (без перерыва), получаю исключение времени выполнения, как я могу решить эту проблему?

если это невозможно, то как я могу обработать это исключение?

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

                    }
                });

Журнал:

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)

Примечание. Как и в Pudding Camera, они позволяют пользователю непрерывно нажимать на кнопку «Захват», но они никогда не будут отображать исключение, если вы сделаете 50 кликов, будет захвачено 10 или больше изображений, каждое изображение через определенное время, но не показывает исключение, как я получаю в своем коде, так же, как я могу обработать это исключение?

Полный код:

@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;

    }


}

person Sun    schedule 12.02.2014    source источник
comment
Вы добавили необходимые разрешения в манифест?   -  person Seshu Vinay    schedule 12.02.2014
comment
все работает нормально, просто хочу контролировать непрерывный щелчок и хочу контролировать исключение   -  person Sun    schedule 12.02.2014
comment
Вы должны позвонить startPreview() после takePicture()   -  person Kishore    schedule 12.02.2014
comment
1. Пожалуйста, добавьте в свой вопрос код onPictureTaken(). 2. Когда используется onTouchEvent()? 3. Вы хотите сделать снимок, нажав кнопку? 4. Возникает ли RuntimeException при однократном нажатии кнопки?   -  person Melquiades    schedule 12.02.2014
comment
@Melquiades привет, братан, я разместил полный код, пожалуйста, проверьте сейчас, получение RuntimeException при многократном нажатии без перерыва, в противном случае работает нормально   -  person Sun    schedule 12.02.2014
comment
Вы можете использовать флаг, чтобы ограничить вызов takePicture() скоростью, с которой сохраняются ваши изображения. Подробнее в ответе.   -  person Melquiades    schedule 12.02.2014


Ответы (5)


Во-первых, перехватывайте свои исключения в onPictureTaken, оставлять пустые разделы перехвата не рекомендуется. Затем я бы добавил флаг, который предотвратит вызов takePicture() во время сохранения предыдущего изображения. Позже в вашей кнопке onClick вы проверите, можно ли вызывать takePicture().

  1. Объявите флаг как член вашей деятельности:

    private boolean safeToTakePicture = false;
    
  2. В surfaceChanged() просто установите флаг в значение true после вызова startPreview():

    camera.startPreview();
    safeToTakePicture = true;
    
  3. В вашем слушателе onClick() установите флажок и сделайте снимок, если это можно сделать:

    if (safeToTakePicture) {
        mp.start();
        camera.takePicture(null, null, mPicture); 
        safeToTakePicture = false;
    }
    
  4. В onPictureTaken() снова установите флаг в значение true после сохранения изображения (и добавьте печать исключений):

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

ПРИМЕЧАНИЯ. Как сказано в документации, "Предварительный просмотр должен быть запущен до того, как вы сможете сделать снимок"., поэтому возможным улучшением будет использование setPreviewCallback() для регистрации обратного вызова, который вызываться, когда доступны данные предварительного просмотра, и устанавливать флаг в значение true при вызове onPreviewFrame.

person Melquiades    schedule 12.02.2014
comment
такое удивительное решение :) вы просто гений .. хорошее объяснение, и один небольшой вопрос, что, если я также хочу использовать кнопку камеры по умолчанию для захвата изображения, как в камере пудинга - person Sun; 12.02.2014
comment
почему мой метод реализации не вызвал его start? :( поверхность изменена() - person Ahmad Arslan; 14.07.2014
comment
@Melquiades этот код не работает внутри потока, и я получаю исключение pastie.org/9583142, он принимает первое изображение нормально, но после первого изображения вылетает - person Erum; 22.09.2014
comment
@ErumHannan, можете ли вы опубликовать новый вопрос на SO с вашим кодом и сообщить мне, я посмотрю. - person Melquiades; 22.09.2014
comment
я решил эту проблему, но все же после съемки в цикле я запускаю другое действие, но из нового действия при попытке нажать клавишу «Назад», чтобы вернуться к действию камеры, это приводит к сбою моего приложения, потому что onStop был вызван, и он выпускает камеру, но onStart у меня есть снова запустите камеру, но она не работает @Melquiades - person Erum; 22.09.2014
comment
можете ли вы продолжить обсуждение здесь chat.stackoverflow.com/rooms/26424/iosandroidchaosoverflow - person Erum; 22.09.2014
comment
Я использовал Camera.setPreviewCallback(). У меня это сработало... спасибо, Мелькиадес. - person John; 27.11.2014
comment
звонок camera.startPreview() до того, как takePicture сделал свое дело! - person Muhammad Babar; 04.12.2014
comment
@Melquiades Что такое МП? - person Castor; 19.06.2019
comment
@SoftDev MediaPlayer - см. в исходном вопросе - person Melquiades; 19.06.2019

У меня также была аналогичная проблема. позже я обнаружил, что startPreview очень важен.

_camera.startPreview() Очень важно, прежде чем приступить к проверке takePicutre, ознакомьтесь с пунктами 5 и 6 этой ссылки.

person Make it Simple    schedule 12.02.2014
comment
перед takePicture(..) где onTouchEvent(,..) или кнопка захвата? - person Sun; 12.02.2014
comment
@Sun да, вам нужно вызвать camera.startPreview(), когда задание сохранения будет выполнено (например, в onPictureTaken()), иначе камера не позволит вам сделать другое изображение. - person Patrick; 13.11.2018

Этому может быть много причин, в моем случае я пытался сделать фото без предварительного просмотра (скрытое фото) и использовал SurfaceView, поэтому я заменил его на SurfaceTexture

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

и проблема была решена... P.S. Я получал эту ошибку только на устройствах выше 6.0.

person Tabish    schedule 01.01.2018

Вы забыли позвонить startPreview() на камеру?

Подробнее см. здесь.

person ThaMe90    schedule 12.02.2014

Этот метод поможет вам в попытке решить проблему.

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;
        }
    }
person Ahmad Arslan    schedule 12.02.2014