RuntimeException при съемке с использованием пользовательской камеры - "takePicture failed"

Ошибка возникает внутри CameraFragment - фрагмент, содержащий только FrameLayout (для предварительного просмотра камеры) и ImageButton (используется для захвата изображения). В моем фрагменте у меня есть PictureCallback:

private static Camera.PictureCallback mPicture = new Camera.PictureCallback() {

    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        CameraFragment.DATA=data;
        final int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
        if (permission != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(
                    activity,
                    PERMISSIONS_STORAGE,
                    REQUEST_STORAGE
            );
            return;
        }
        saveImageToDevice();

    }
};

и я получаю экземпляр своей камеры из HandlerThread:

private CameraHandlerThread mThread = null;

private static class CameraHandlerThread extends HandlerThread {
    Handler mHandler = null;
    private Camera handlerCamera;

    CameraHandlerThread() {
        super("CameraHandlerThread");
        start();
        mHandler = new Handler(getLooper());
    }

    synchronized void notifyCameraOpened() {
        notify();
    }

    void openCamera() {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                handlerCamera = getCameraInstance();
                notifyCameraOpened();
            }
        });
        try {
            wait();
        }
        catch (InterruptedException e) {

        }
    }

    public Camera getCamera() {
        return handlerCamera;
    }
}

то я вызываю этот метод (где возникает исключение) в OnCreateView():

private void launchCamera() {
    newOpenCamera();
    mPreview = new CameraPreview(getContext(), mCamera, activity);
    mPreview.setCameraDisplayOrientation(activity, CAMERA_ID, mCamera);
    preview = (FrameLayout) view.findViewById(R.id.tvCamera);
    preview.addView(mPreview);
    ivCaptureImage = (ImageView) view.findViewById(R.id.ivCaptureImage);
    ivCaptureImage.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mCamera.takePicture(null, null, mPicture); 
        }
    });
}

где newOpenCamera:

private void newOpenCamera() {
    if (mThread == null) {
        mThread = new CameraHandlerThread();
    }

    synchronized (mThread) {
        mThread.openCamera();
        mCamera = mThread.getCamera();
    }
}

Я запустил отладчик и вижу, что строка, в которой произошла ошибка (mCamera.takePicture(...) в launchCamera()), вызывается, но ошибка возникает перед PictureCallback. Ошибка:

E/UncaughtException: java.lang.RuntimeException: takePicture failed
        at android.hardware.Camera.native_takePicture(Native Method)
        at android.hardware.Camera.takePicture(Camera.java:1523)
        at android.hardware.Camera.takePicture(Camera.java:1468)
        at com.myapp.myapp.camera.CameraFragment$2.onClick(CameraFragment.java:175)
        at android.view.View.performClick(View.java:5697)
        at android.view.View$PerformClick.run(View.java:22526)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:158)
        at android.app.ActivityThread.main(ActivityThread.java:7229)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
05-28 17:09:22.600 1171-1171/com.myapp.myapp E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.myapp.myapp, PID: 1171
    java.lang.RuntimeException: takePicture failed
        at android.hardware.Camera.native_takePicture(Native Method)
        at android.hardware.Camera.takePicture(Camera.java:1523)
        at android.hardware.Camera.takePicture(Camera.java:1468)
        at com.myapp.myapp.camera.CameraFragment$2.onClick(CameraFragment.java:175)
        at android.view.View.performClick(View.java:5697)
        at android.view.View$PerformClick.run(View.java:22526)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:158)
        at android.app.ActivityThread.main(ActivityThread.java:7229)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)

Кто-нибудь знает, что может быть неправильным? Как вы можете видеть, я всегда получаю две одинаковые ошибки с каждым сделанным снимком.

Любая помощь высоко ценится, приветствует.

Редактировать:

Я поставил охранников, чтобы остановить одиночные касания, регистрирующиеся как multi, как описано здесь: java.lang.RuntimeException: takePicture failed

Еще не повезло

Ответы

Ответ 2

Я думаю, что вы забыли вызвать метод startPreview() на свой объект камеры. Из официальной документации:

6.Important: вызвать startPreview(), чтобы начать обновление поверхности предварительного просмотра. Прежде чем вы сможете сделать снимок.

https://developer.android.com/reference/android/hardware/Camera

Ответ 3

Используйте этот способ для открытия камеры с использованием поверхностного вида Java Code

public class CameraOverlayActivity extends AppCompatActivity implements SurfaceHolder.Callback {
    Camera camera;
    SurfaceView surfaceView;
    SurfaceHolder surfaceHolder;
    boolean previewing = false;
    LayoutInflater controlInflater = null;

    private File videoPath;
    private ImageView imgCapture;
    int camBackId;
    String strVideoFolderPath;
    private ProgressDialog progressDialog;
    Camera.Parameters parameters;
    public boolean hasFlash;
    public boolean camRotation = false;
    private RelativeLayout relativeLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera_overlay);

        relativeLayout = findViewById(R.id.control);

        camBackId = Camera.CameraInfo.CAMERA_FACING_BACK;
        hasFlash = this.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
        surfaceView = findViewById(R.id.surface);
        progressDialog = new ProgressDialog(this);
        progressDialog.setTitle(null);
        progressDialog.setCancelable(false);
        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(this);
        strVideoFolderPath = Environment.getExternalStorageDirectory().getAbsolutePath();
        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        controlInflater = LayoutInflater.from(getBaseContext());
        videoPath = new File(Environment.getExternalStorageDirectory() + "/sw/raw");
        if (videoPath.exists()) {
            if (videoPath.isDirectory()) {
                if (videoPath.listFiles().length != 0) {
                    String[] children = videoPath.list();
                    for (int i = 0; i < children.length; i++) {
                        new File(videoPath, children[i]).delete();
                    }
                }
            }
        }
        if (!videoPath.exists()) {
            videoPath.mkdirs();
        }

        imgCapture = findViewById(R.id.img_capture);
        imgCapture.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (camera != null) {
                    if (previewing) {
                        System.gc();
                        try {
                            capturePhoto();
                        } catch (Exception e) {
                            Log.v("ERRORR", e.getMessage());
                            e.printStackTrace();
                        }
                    }
                }
            }
        });

    }

    public void capturePhoto() throws Exception {
        camera.takePicture(null, null, myPictureCallback_JPG);

    }

    @Override
    protected void onResume() {
        super.onResume();
        Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
    }

    Camera.PictureCallback myPictureCallback_JPG = new Camera.PictureCallback() {

        @Override
        public void onPictureTaken(byte[] arg0, Camera arg1) {
            // TODO Auto-generated method stub
            FileOutputStream outStream = null;
            //camera.startPreview();
            try {
                Date date = new Date();
                String filename = "/rec" + date.toString().replace(" ", "_").replace(":", "_") + ".jpg";
                filename = filename.replace("+", "");
                File file = new File(Environment.getExternalStorageDirectory() + "/Switch It");
                if (!file.exists())
                    file.mkdirs();
                outStream = new FileOutputStream(file + filename);
                outStream.write(arg0);
                outStream.close();
                Log.v("File_Path", file.getAbsolutePath());
                Intent returnIntent = new Intent();
                returnIntent.putExtra("img_capture", file.getAbsolutePath() + filename);
                setResult(Activity.RESULT_OK, returnIntent);
                finish();
            } catch (FileNotFoundException e) {
                Log.e("ERROR 1", e.getMessage());
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
                Log.e("ERROR 2", e.getMessage());
            } finally {
            }
        }
    };


    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
                               int height) {
        // TODO Auto-generated method stub
        if (previewing) {
            camera.stopPreview();
            previewing = false;
        }

        if (camera != null) {
            try {
                camera.setPreviewDisplay(surfaceHolder);
                parameters = camera.getParameters();
                if (getPackageManager().hasSystemFeature("android.hardware.camera.autofocus")) {
                    parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
                }

                camera.startPreview();
                if (hasFlash) {
                    parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
                }
                camera.setParameters(parameters);
                previewing = true;

            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // TODO Auto-generated method stub
        camera = Camera.open();
        if (android.os.Build.VERSION.SDK_INT > 7) {
            Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
            if (display.getRotation() == Surface.ROTATION_0) {
                camera.setDisplayOrientation(90);
                camRotation = true;
            }
        }


    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // TODO Auto-generated method stub
        if (camera != null) {
            camera.stopPreview();
            camera.release();
            camera = null;
            previewing = false;
        }
    }

}

XML-код

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/control"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <SurfaceView
        android:id="@+id/surface"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />




    <ImageView
        android:id="@+id/img_capture"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_marginRight="5dp"
        android:src="@drawable/ic_lens_black_24dp" />


</RelativeLayout>

Ответ 4

Проверьте, установлено ли разрешение на использование камеры для данного конкретного приложения. Перейдите в Настройки → Приложения → "Имя вашего приложения" → Разрешения → Включите разрешение для камеры. Также убедитесь, что разрешение указано в файле manifest.xml. Он задается как:

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Проверьте эту ссылку для получения более подробной информации:

https://developer.android.com/guide/topics/media/camera

Ответ 5

Попробуйте это для меня, и проверьте разрешение, указанное в файле манифеста.

 mCamera = Camera.open(id);
 setCameraDisplayOrientation(mContext, id, mCamera);
 mCamera.setPreviewDisplay(new DummySurfaceHolder());
 SurfaceTexture st = new SurfaceTexture(MODE_PRIVATE);
 mCamera.setPreviewTexture(st);

 mCamera.startPreview();
 mCamera.autoFocus(new Camera.AutoFocusCallback() {
    @Override
     public void onAutoFocus(boolean b, Camera camera) {

      try {
         Thread.sleep(500);
       } catch (InterruptedException e) {
         e.printStackTrace();
       }

      mCamera.takePicture(null, null, null, new PictureCapture(mContext));

       }
     });