web-dev-qa-db-ja.com

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;

    }


}
41
Sun

まず、onPictureTakenで例外をキャッチします。空のキャッチセクションを残すことはお勧めできません。次に、前の画像が保存されている間にtakePicture()を呼び出さないようにするフラグを追加します。ボタンonClickの後で、takePicture()を呼び出しても問題ないかどうかを確認します。

  1. アクティビティのメンバーとしてフラグを宣言します。

    _private boolean safeToTakePicture = false;
    _
  2. surfaceChanged()では、startPreview()を呼び出した後にフラグをtrueに設定するだけです。

    _camera.startPreview();
    safeToTakePicture = true;
    _
  3. onClick()リスナーでフラグを確認し、OKの場合は写真を撮ります。

    _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()を使用してプレビューデータが利用可能なときに呼び出され、onPreviewFrameが呼び出されたときにフラグをtrueに設定します。

63
Melquiades

私も同様の問題を抱えていました。後でstartPreviewが非常に重要であることがわかりました。

_camera.startPreview()は、takePicutreがポイント5および6をチェックアウトする前に非常に重要です このリンク内

8
Make it Simple

私の場合、これには多くの理由があります。プレビューなしで写真を撮ろうとして(隠された写真)、SurfaceViewを使用していたので、SurfaceTextureに置き換えました

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

問題は解決しました... P.S 6.0以上のデバイスでのみこのエラーが発生していました

4
Tabish

カメラでstartPreview()を呼び出すのを忘れましたか?

詳細については、 here を参照してください。

2
ThaMe90

この方法は、問題の解決に役立ちます。

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