繁体   English   中英

如何使用 Camera2 API 重新打开相机?

[英]How to reopen camera using Camera2 API?

我正在使用 Camera2 API 创建自定义相机。 我想在使用相机预览(继续捕获图像)保存图像后重新打开相机。 我试图在保存图像后重新打开相机,但它显示错误。

android.view.ViewRootImpl$CalledFromWrongThreadException:只有创建视图层次结构的原始线程才能触摸其视图。

private final TextureView.SurfaceTextureListener mSurfaceTextureListener
        = new TextureView.SurfaceTextureListener() {

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
        openCamera(width, height);
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
        configureTransform(width, height);
    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
        return true;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture texture) {
    }

};

打开相机方法

private void openCamera(int width, int height) {
        if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA)
                != PackageManager.PERMISSION_GRANTED) {
            requestCameraPermission();
            return;
        }
        setUpCameraOutputs(width, height);
        configureTransform(width, height);
        Activity activity = getActivity();
        CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
        try {
            if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
                throw new RuntimeException("Time out waiting to lock camera opening.");
            }
            manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
        }
    }

重新打开相机方法

 public void reopenCamera() {
    Log.d("REOPENCAMERA", "reopenCamera: called.");
    if (mTextureView.isAvailable()) {
        Log.d(TAG, "reopenCamera: a surface is available.");
        if(stillCapturedImage){
            capture++;
            changeFrame(capture);
            openCamera(mTextureView.getWidth(), mTextureView.getHeight());
        }else{
            openCamera(mTextureView.getWidth(), mTextureView.getHeight());
        }
    } else {
        Log.d(TAG, "reopenCamera: no surface is available.");
        mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
    }

}

捕获会话

private CameraCaptureSession.CaptureCallback mCaptureCallback
        = new CameraCaptureSession.CaptureCallback() {

    private void process(CaptureResult result) {
        switch (mState) {
            case STATE_PREVIEW: {
                // We have nothing to do when the camera preview is working normally.
                break;
            }
            case STATE_WAITING_LOCK: {
                Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
                if (afState == null) {
                    captureStillPicture();
                } else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
                        CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
                    // CONTROL_AE_STATE can be null on some devices
                    Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                    if (aeState == null ||
                            aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
                        mState = STATE_PICTURE_TAKEN;
                        captureStillPicture();
                    } else {
                        runPrecaptureSequence();
                    }
                }
                else if(afState == CaptureResult.CONTROL_AF_STATE_INACTIVE){
                    mState = STATE_PICTURE_TAKEN;
                    captureStillPicture();
                }
                break;
            }
            case STATE_WAITING_PRECAPTURE: {
                // CONTROL_AE_STATE can be null on some devices
                Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                if (aeState == null ||
                        aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
                        aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {
                    mState = STATE_WAITING_NON_PRECAPTURE;
                }
                break;
            }
            case STATE_WAITING_NON_PRECAPTURE: {
                // CONTROL_AE_STATE can be null on some devices
                Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
                    mState = STATE_PICTURE_TAKEN;
                    captureStillPicture();
                }
                break;
            }
        }
    }

    @Override
    public void onCaptureProgressed(@NonNull CameraCaptureSession session,
                                    @NonNull CaptureRequest request,
                                    @NonNull CaptureResult partialResult) {
        process(partialResult);
    }

    @Override
    public void onCaptureCompleted(@NonNull CameraCaptureSession session,
                                   @NonNull CaptureRequest request,
                                   @NonNull TotalCaptureResult result) {
        process(result);
    }

};

保存图像方法

 private void saveTempImageToStorage(){
    Log.d(TAG, "saveTempImageToStorage: saving temp image to disk.");
    final ICallback callback = new ICallback() {
        @Override
        public void done(Exception e) {
            if(e == null){
                Log.d(TAG, "onImageSavedCallback: image saved!");
                mBackgroundImageRotater = new BackgroundImageRotater(getActivity());
                mBackgroundImageRotater.execute();
                mIsImageAvailable = true;
                mCapturedImage.close();
            }
            else{
                Log.d(TAG, "onImageSavedCallback: error saving image: " + e.getMessage());
                showSnackBar("Error displaying image", Snackbar.LENGTH_SHORT);
            }
        }
    };

    ImageSaver imageSaver = new ImageSaver(
            mCapturedImage,
            getActivity().getExternalFilesDir(null),
            callback
    );
    mBackgroundHandler.post(imageSaver);
}

重新打开相机方法应该没问题,但是您需要将一些正在更新 UI 的后台任务移动到主线程。

示例代码:

runOnUiThread(new Runnable() {

    @Override
    public void run() {

        // The code which updates your UI

    }
});

最后,请确保您正确使用生命周期方法。

您可以通过官方文档找到更多信息

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM