Android 相机预览控件详解

在安卓开发中,创建一个相机应用通常需要展示实时的相机预览。为了实现这一功能,Android 提供了相机预览控件,让我们可以轻松地在应用中嵌入相机画面。本文将详细介绍如何使用 Android 的相机预览控件,并提供实例代码以及类图说明。

1. 相机预览控件概述

相机预览控件允许开发者获取设备相机的实时视频流,以便进行拍照、录像及其他图像处理操作。Android 提供了多种方式来实现相机预览,这里我们主要探讨使用 Camera2 API 来实现。

2. Camera2 API

Camera2 API 是 Android 5.0(Lollipop)引入的,提供了强大的相机控制功能。与早期版本的 API 相比,它不仅能够支持更多的设备,还可以实现更复杂的功能,比如高清图像捕捉和更高帧率的视频流。

2.1 Camera2 API 的基本结构

在使用 Camera2 API 之前,我们需要了解其基本结构。主要类有:

  • CameraManager: 管理设备的相机。
  • CameraDevice: 表示相机设备实例,负责打开和关闭相机。
  • CameraCaptureSession: 用于处理相机的捕获请求。
  • CaptureRequest: 具体的捕获请求设置。
classDiagram
    class CameraController {
        +CameraManager cameraManager
        +CameraDevice cameraDevice
        +CameraCaptureSession captureSession
        +startCamera()
        +stopCamera()
        +createCameraPreviewSession()
    }

3. 实现相机预览控件

下面我们将实现一个简单的相机预览控件,代码将分为几个主要部分。

3.1 申请必要的权限

首先,我们需要在 AndroidManifest.xml 中申请相机权限:

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

3.2 创建相机控制器类

接下来,我们定义一个 CameraController 类,用于封装相机的操作:

import android.content.Context;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class CameraController {
    private CameraManager cameraManager;
    private CameraDevice cameraDevice;
    private CameraCaptureSession captureSession;
    private Context context;
    private SurfaceView surfaceView;

    public CameraController(Context context, SurfaceView surfaceView) {
        this.context = context;
        this.surfaceView = surfaceView;
        cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
    }

    public void startCamera() {
        try {
            String cameraId = cameraManager.getCameraIdList()[0]; // 获取相机ID
            cameraManager.openCamera(cameraId, new CameraDevice.StateCallback() {
                @Override
                public void onOpened(CameraDevice camera) {
                    cameraDevice = camera;
                    createCameraPreviewSession();
                }

                @Override
                public void onDisconnected(CameraDevice camera) {
                    camera.close();
                }

                @Override
                public void onError(CameraDevice camera, int error) {
                    camera.close();
                    cameraDevice = null;
                }
            }, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    public void stopCamera() {
        if (cameraDevice != null) {
            cameraDevice.close();
            cameraDevice = null;
        }
    }

    private void createCameraPreviewSession() {
        try {
            SurfaceHolder holder = surfaceView.getHolder();
            holder.addCallback(new SurfaceHolder.Callback() {
                @Override
                public void surfaceCreated(SurfaceHolder holder) {
                    try {
                        CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                        builder.addTarget(holder.getSurface());
                        cameraDevice.createCaptureSession(Arrays.asList(holder.getSurface()), new CameraCaptureSession.StateCallback() {
                            @Override
                            public void onConfigured(CameraCaptureSession session) {
                                captureSession = session;
                                try {
                                    captureSession.setRepeatingRequest(builder.build(), null, null);
                                } catch (CameraAccessException e) {
                                    e.printStackTrace();
                                }
                            }

                            @Override
                            public void onConfigureFailed(CameraCaptureSession session) {
                                // 处理失败
                            }
                        }, null);
                    } catch (CameraAccessException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { }

                @Override
                public void surfaceDestroyed(SurfaceHolder holder) { }
            });
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }
}

3.3 在 Activity 中使用相机控件

Activity 中,我们需要准备一个 SurfaceView 并使用我们的 CameraController

import android.os.Bundle;
import android.view.SurfaceView;
import androidx.appcompat.app.AppCompatActivity;

public class CameraActivity extends AppCompatActivity {
    private CameraController cameraController;
    private SurfaceView surfaceView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera);
        surfaceView = findViewById(R.id.surfaceView);
        cameraController = new CameraController(this, surfaceView);
        cameraController.startCamera();
    }

    @Override
    protected void onPause() {
        super.onPause();
        cameraController.stopCamera();
    }
}

3.4 布局文件

最后,我们需要在 res/layout/activity_camera.xml 中定义 SurfaceView

<RelativeLayout xmlns:android="
    android:layout_width="match_parent"
    android:layout_height="match_parent">

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

4. 结论

通过上述步骤,你可以很方便地在 Android 应用中实现相机预览功能。借助 Camera2 API,你可以获得更高质量的相机控制。在实际项目中,还可以根据需求添加更多的功能,比如照片保存、录像和美颜效果等。

希望本文能为你提供关于 Android 相机预览控件的基本理解及实现方式,祝你在 Android 开发的道路上越走越远!