Android Studio中如何保持相机持续开启?
Hey there! I get your frustration with the current camera flow—having to go back and re-launch the camera every time you want another photo is definitely clunky. Let's break down why this happens and how to fix it properly.
The Root Problem
The MediaStore.ACTION_IMAGE_CAPTURE Intent is designed explicitly for single-shot photo capture. Once the user takes a photo, the system camera app returns control to your original Activity by default. There's no built-in way to make this Intent support continuous shooting across all devices (since system camera apps vary by manufacturer).
The Best Solution: Build a Custom Camera UI with CameraX
To give users the flexibility to take one or multiple photos without leaving the camera view, the most reliable approach is to implement a custom camera interface using CameraX (Jetpack's camera library). It's easy to integrate, works across Android 5.0+, and gives you full control over the capture flow.
Step 1: Add CameraX Dependencies
First, add these dependencies to your app-level build.gradle file:
dependencies { def camerax_version = "1.3.0" implementation "androidx.camera:camera-core:$camerax_version" implementation "androidx.camera:camera-camera2:$camerax_version" implementation "androidx.camera:camera-lifecycle:$camerax_version" implementation "androidx.camera:camera-view:$camerax_version" }
Step 2: Create the Camera Layout
Add a preview view and capture button to your layout (e.g., activity_camera.xml):
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.camera.view.PreviewView android:id="@+id/previewView" android:layout_width="match_parent" android:layout_height="match_parent"/> <Button android:id="@+id/captureBtn" android:layout_width="72dp" android:layout_height="72dp" android:background="@drawable/round_button" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_marginBottom="32dp"/> </RelativeLayout>
Step 3: Implement the Camera Logic
Here's the full Activity code to handle continuous capture. Users can tap the button as many times as they want to take photos, and the camera preview stays active between shots:
import androidx.appcompat.app.AppCompatActivity; import androidx.camera.core.CameraSelector; import androidx.camera.core.ImageCapture; import androidx.camera.core.ImageCaptureException; import androidx.camera.core.Preview; import androidx.camera.lifecycle.ProcessCameraProvider; import androidx.camera.view.PreviewView; import androidx.core.content.ContextCompat; import android.content.ContentValues; import android.os.Bundle; import android.provider.MediaStore; import android.widget.Button; import android.widget.Toast; import com.google.common.util.concurrent.ListenableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; public class CustomCameraActivity extends AppCompatActivity { private ImageCapture imageCapture; private ListenableFuture<ProcessCameraProvider> cameraProviderFuture; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_camera); PreviewView previewView = findViewById(R.id.previewView); Button captureBtn = findViewById(R.id.captureBtn); // Initialize camera provider cameraProviderFuture = ProcessCameraProvider.getInstance(this); cameraProviderFuture.addListener(() -> { try { ProcessCameraProvider cameraProvider = cameraProviderFuture.get(); bindCameraUseCases(cameraProvider, previewView); } catch (ExecutionException | InterruptedException e) { Toast.makeText(this, "Camera initialization failed!", Toast.LENGTH_SHORT).show(); } }, ContextCompat.getMainExecutor(this)); // Handle capture button clicks captureBtn.setOnClickListener(v -> takePhoto()); } private void bindCameraUseCases(ProcessCameraProvider cameraProvider, PreviewView previewView) { // Configure preview use case Preview preview = new Preview.Builder().build(); preview.setSurfaceProvider(previewView.getSurfaceProvider()); // Select back camera CameraSelector cameraSelector = new CameraSelector.Builder() .requireLensFacing(CameraSelector.LENS_FACING_BACK) .build(); // Configure image capture use case imageCapture = new ImageCapture.Builder() .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) .build(); // Bind use cases to lifecycle cameraProvider.unbindAll(); cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture); } private void takePhoto() { if (imageCapture == null) return; // Prepare output file details ContentValues contentValues = new ContentValues(); contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, "MyPhoto_" + System.currentTimeMillis()); contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg"); ImageCapture.OutputFileOptions outputOptions = new ImageCapture.OutputFileOptions .Builder(getContentResolver(), MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues) .build(); // Execute photo capture Executor executor = ContextCompat.getMainExecutor(this); imageCapture.takePicture(outputOptions, executor, new ImageCapture.OnImageSavedCallback() { @Override public void onImageSaved(ImageCapture.OutputFileResults outputFileResults) { // Photo saved successfully - you can store the URI in a list here Toast.makeText(CustomCameraActivity.this, "Photo saved!", Toast.LENGTH_SHORT).show(); // Camera stays active - user can tap again for another photo } @Override public void onError(ImageCaptureException exception) { Toast.makeText(CustomCameraActivity.this, "Capture failed: " + exception.getMessage(), Toast.LENGTH_SHORT).show(); } }); } }
Step 4: Handle Permissions
Don't forget to add the required permissions to your AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32"/> <uses-feature android:name="android.hardware.camera" android:required="true"/> <uses-feature android:name="android.hardware.camera.autofocus"/>
You'll also need to request runtime permissions before launching the camera. Add this code to your Activity:
import android.Manifest; import android.content.pm.PackageManager; import android.widget.Toast; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; private static final int REQUEST_PERMISSIONS = 100; private static final String[] REQUIRED_PERMISSIONS = {Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_camera); if (!allPermissionsGranted()) { ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_PERMISSIONS); } else { // Initialize camera logic here } } private boolean allPermissionsGranted() { for (String permission : REQUIRED_PERMISSIONS) { if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) { return false; } } return true; } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_PERMISSIONS) { if (allPermissionsGranted()) { // Initialize camera logic here } else { Toast.makeText(this, "Permissions are required to use the camera!", Toast.LENGTH_SHORT).show(); finish(); } } }
How This Solves Your Problem
- Users can take one or multiple photos without leaving the camera view.
- The preview stays active between shots, so no need to re-launch the camera every time.
- You have full control over where photos are saved and can easily track all captured images (e.g., store their URIs in a list to process later).
内容的提问来源于stack exchange,提问作者SpaceSloth

