在Android中实现在后台拍照(静默)

Source

代码解释:

  • CameraService 是一个后台服务,用于管理摄像头的打开、预览以及图像的捕获和保存。
  • onBind 方法返回服务的绑定接口。
  • onCreate 方法初始化服务。
  • onStartCommand 方法在服务启动时调用,启动后台线程并打开摄像头。
  • onDestroy 方法在服务销毁时调用,关闭摄像头并停止后台线程。
  • startBackgroundThreadstopBackgroundThread 方法分别启动和停止后台线程。
  • openCamera 方法打开摄像头并设置图像读取器。
  • chooseCamera 方法选择后置摄像头。
  • createCameraPreview 方法创建摄像头预览会话。
  • updatePreview 方法更新预览画面。
  • closeCamera 方法关闭摄像头和图像读取器。
  • saveImageToStorage 方法将捕获的图像保存到存储中。
  • createImageFile 方法创建一个用于保存图像的临时文件。
    import android.annotation.SuppressLint;
    import android.app.Service;
    import android.content.Context;
    import android.content.Intent;
    import android.graphics.ImageFormat;
    import android.hardware.camera2.CameraAccessException;
    import android.hardware.camera2.CameraCaptureSession;
    import android.hardware.camera2.CameraCharacteristics;
    import android.hardware.camera2.CameraDevice;
    import android.hardware.camera2.CameraManager;
    import android.hardware.camera2.CameraMetadata;
    import android.hardware.camera2.CaptureRequest;
    import android.media.Image;
    import android.media.ImageReader;
    import android.os.Binder;
    import android.os.Handler;
    import android.os.HandlerThread;
    import android.os.IBinder;
    import android.util.Log;
    import android.view.Surface;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.nio.ByteBuffer;
    import java.text.SimpleDateFormat;
    import java.util.Arrays;
    import java.util.Date;
    
    public class CameraService extends Service {
    
        private static final String TAG = "CameraService";
        private CameraDevice cameraDevice;
        private CameraCaptureSession cameraCaptureSession;
        private CaptureRequest.Builder captureRequestBuilder;
        private ImageReader imageReader;
    
        private Handler backgroundHandler;
        private HandlerThread backgroundThread;
    
        private final IBinder binder = new LocalBinder();
    
        public class LocalBinder extends Binder {
            CameraService getService() {
                return CameraService.this;
            }
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return binder;
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            startBackgroundThread(); // 启动后台线程
            openCamera(); // 打开摄像头
            return START_NOT_STICKY;
        }
    
        @Override
        public void onDestroy() {
            closeCamera(); // 关闭摄像头
            stopBackgroundThread(); // 停止后台线程
            super.onDestroy();
        }
    
        private void startBackgroundThread() {
            backgroundThread = new HandlerThread("CameraBackground");
            backgroundThread.start();
            backgroundHandler = new Handler(backgroundThread.getLooper());
        }
    
        private void stopBackgroundThread() {
            backgroundThread.quitSafely();
            try {
                backgroundThread.join();
                backgroundThread = null;
                backgroundHandler = null;
            } catch (InterruptedException e) {
                Log.e(TAG, "Interrupted while waiting for background thread to close", e);
            }
        }
    
        @SuppressLint("MissingPermission")
        private void openCamera() {
            CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
            try {
                String cameraId = chooseCamera(manager); // 选择摄像头
                CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
    
                imageReader = ImageReader.newInstance(
                        720, 1080, ImageFormat.JPEG, 1);
                imageReader.setOnImageAvailableListener(
                        reader -> {
                            Image image = reader.acquireLatestImage();
                            // 处理图像数据,保存到沙箱
                            saveImageToStorage(image);
                            image.close();
                        },
                        backgroundHandler);
    
                manager.openCamera(cameraId, new CameraDevice.StateCallback() {
                    @Override
                    public void onOpened(CameraDevice camera) {
                        cameraDevice = camera;
                        createCameraPreview(); // 创建摄像头预览
                    }
    
                    @Override
                    public void onDisconnected(CameraDevice camera) {
                        cameraDevice.close();
                    }
    
                    @Override
                    public void onError(CameraDevice camera, int error) {
                        cameraDevice.close();
                        cameraDevice = null;
                    }
                }, backgroundHandler);
            } catch (CameraAccessException e) {
                Log.e(TAG, "Cannot access the camera.", e);
            }
        }
    
        private String chooseCamera(CameraManager manager) throws CameraAccessException {
            for (String cameraId : manager.getCameraIdList()) {
                CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
                if (characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_BACK) {
                    return cameraId; // 返回后置摄像头的ID
                }
            }
            return manager.getCameraIdList()[0]; // 默认返回第一个摄像头
        }
    
        private void createCameraPreview() {
            try {
                Surface surface = imageReader.getSurface();
    
                captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                captureRequestBuilder.addTarget(surface);
    
                cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() {
                    @Override
                    public void onConfigured(CameraCaptureSession session) {
                        if (cameraDevice == null) {
                            return;
                        }
                        cameraCaptureSession = session;
                        updatePreview(); // 更新预览
                    }
    
                    @Override
                    public void onConfigureFailed(CameraCaptureSession session) {
                        Log.e(TAG, "Failed to configure camera preview.");
                    }
                }, null);
            } catch (CameraAccessException e) {
                Log.e(TAG, "Error creating camera preview.", e);
            }
        }
    
        private void updatePreview() {
            if (cameraDevice == null) {
                return;
            }
    
            captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
    
            try {
                cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, backgroundHandler);
            } catch (CameraAccessException e) {
                Log.e(TAG, "Error updating preview.", e);
            }
        }
    
        private void closeCamera() {
            if (cameraCaptureSession != null) {
                cameraCaptureSession.close();
                cameraCaptureSession = null;
            }
    
            if (cameraDevice != null) {
                cameraDevice.close();
                cameraDevice = null;
            }
    
            if (imageReader != null) {
                imageReader.close();
                imageReader = null;
            }
        }
    
        private void saveImageToStorage(Image image) {
            ByteBuffer buffer = image.getPlanes()[0].getBuffer();
            byte[] bytes = new byte[buffer.remaining()];
            buffer.get(bytes);
    
            File imageFile = null;
            try {
                imageFile = createImageFile(); // 创建图像文件
            } catch (IOException e) {
                Log.e(TAG, "Error creating image file.", e);
            }
            try (FileOutputStream output = new FileOutputStream(imageFile)) {
                output.write(bytes);
                closeCamera(); // 关闭摄像头
                stopBackgroundThread(); // 停止后台线程
                Log.d(TAG, "Image saved: " + imageFile.getAbsolutePath());
            } catch (IOException e) {
                Log.e(TAG, "Error saving image.", e);
            }
        }
    
        private File createImageFile() throws IOException {
            String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
            String imageFileName = "JPEG_" + timeStamp + "_";
            File storageDir = getFilesDir();
            return File.createTempFile(imageFileName, ".jpg", storageDir); // 创建临时图像文件
        }
    }
  • 提示:需在activity中启动CameraService服务,包括在AndroidManifest.xml添加权限,开启相机权限等等