当切换相机时,Android相机预览会冻结吗?

3
我正在为我的应用程序编写自定义相机。当使用后置或前置摄像头打开活动时,它的工作正常。但是,在活动内切换相机时我遇到了很大的困难。
当我点击切换相机按钮时,预览会冻结,什么也不会发生。我尝试了与相机和预览相关的其他问题中提出的答案和提示,但没有任何作用。
这是我的活动内容:
public class CameraActivity extends Activity implements SurfaceHolder.Callback {

    //================================================================================
    // Properties
    //================================================================================

    // Tag
    private final String TAG = "CameraActivity";

    // Camera and CameraPreview objects
    private Camera mCamera;

    // SurfaceHolder object
    private SurfaceHolder mSurfaceHolder;
//    private CameraPreview mPreview;

    // ImageButtons
    private ImageButton captureButton;
    private ImageButton camSwitchButton;

    // Picture previewLayout
    FrameLayout previewLayout;
    SurfaceView preview;

    // Current camera is facing FRONT or BACK
    private int currentCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;

    // Picture taking callback
    private Camera.PictureCallback mPictureCallback;

    //================================================================================
    // Methods
    //================================================================================

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

        // Activity with no notification bar
        requestWindowFeature(Window.FEATURE_NO_TITLE);

        // Set content view
        setContentView(R.layout.activity_camera);

        // Initialize activity and previews
        InitActivity();
        InitPreview();

        // Set onClicks
    }

    /**
     * Initialize activity views
     */
    private void InitActivity() {

        // Create an instance of Camera
        mCamera = GetCameraInstance(currentCameraId);

        // Set the SurfaceView
        preview = (SurfaceView) findViewById(R.id.camera_preview);
        mSurfaceHolder = preview.getHolder();
        mSurfaceHolder.addCallback(this);

    }

    /**
     * Initialize the camera preview
     */
    private void InitPreview() {

        if (mCamera != null) {

            try {
                mCamera.setPreviewDisplay(mSurfaceHolder);
            } catch (IOException e) {
                // log
            }

            mCamera.startPreview();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();

        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.release(); // release the camera for other applications
            // mCamera = null;
        }
    }

    @Override
    protected void onResume() {
        super.onResume();

        if (mCamera == null) {
            InitActivity();
            InitPreview();
        }
    }

    /**
     * Get camera instance
     * @return Camera instance (null if doesn't exist)
     */
    private Camera GetCameraInstance(int camid) {

        Camera c = null;

        try {

            c = Camera.open(camid); // attempt to get a Camera instance

            Camera.Parameters campar = c.getParameters();

            // Set auto-focus
            if (getPackageManager().hasSystemFeature("android.hardware.camera.autofocus")) {
                campar.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
            }

            c.setParameters(campar);

        }
        catch (Exception e){
            // log
        }

        return c; // returns null if camera is unavailable
    }

    /**
     * Switch the camera from front to back and vica verca
     */
    private void SwitchCamera() {

        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.release();
            // mCamera = null;
        }

        //swap the id of the camera to be used
        if (currentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK) {
            currentCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
        }
        else currentCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;

        // Remove the view and re-add it
        ViewGroup rootView = (ViewGroup) preview.getParent();
        rootView.removeView(previewLayout);

        mCamera = GetCameraInstance(currentCameraId);

        InitActivity();

    }

    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        Logger.Log(TAG, "SurfaceCreated");
        InitPreview();
    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {    
        // Return if no surface found
        if (mSurfaceHolder.getSurface() == null) {
            return;
        }

        // Start preview with new settings
        Camera.Parameters params = mCamera.getParameters();
        boolean isPortrait = IsPortrait();

        // Configure the parameters (so the image is showing correctly)
        ConfigureCameraParameters(params, isPortrait);

        // Start preview
        InitPreview();

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {

        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
    }

    /**
     * Configure the camer parameters
     * @param cameraParams Camera parameters
     * @param isPortrait Is the camera in portrait mode?
     */
    protected void ConfigureCameraParameters(Camera.Parameters cameraParams, boolean isPortrait) {

        int angle;

        Display display = getWindowManager().getDefaultDisplay();

        // Correct the orientation
        switch (display.getRotation()) {

            case Surface.ROTATION_0: // This is display orientation
                angle = 90; // This is camera orientation
                break;
            case Surface.ROTATION_90:
                angle = 0;
                break;
            case Surface.ROTATION_180:
                angle = 270;
                break;
            case Surface.ROTATION_270:
                angle = 180;
                break;
            default:
                angle = 90;
                break;
        }

        mCamera.setDisplayOrientation(angle);
        mCamera.setParameters(cameraParams);
    }

    /**
     * Check whether the camera is in portrait mode
     * @return True|False
     */
    private boolean IsPortrait() {
        return (getResources().getConfiguration().orientation
                == Configuration.ORIENTATION_PORTRAIT);
    }
}

清单文件中的权限:

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

如果有人能帮忙,我会非常感激。

1个回答

2
你已经非常接近正确的方法了,每次切换相机时无需销毁表面视图,只需要销毁相机会话,并确保重新将相机连接到表面视图以便显示。在Razr Max上,我遇到了一些前置后置逻辑的问题,所以我只是将其切换为1和0。
    private void SwitchCamera() {

    if (mCamera != null) {
        mCamera.stopPreview();
        mCamera.release();
         mCamera = null;
    }

    //swap the id of the camera to be used
    if (currentCameraId == Camera.CameraInfo.CAMERA_FACING_FRONT) {
        currentCameraId = 0;
    } else  {
        currentCameraId = 1;
    }

    mCamera = GetCameraInstance(currentCameraId);

    InitPreview();
}

是的,成功了!现在它可以工作了。谢谢。我再次检查后发现,除了不必要地破坏SurfaceView之外,问题在于调用InitActivity()时尝试打开已经打开的相机。 - Mahm00d

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接