使用 Camera API 直接拍照,回調中得到空白/全黑圖片。
startPreview() 後需等待幾幀穩定
public class CameraActivity extends AppCompatActivity {
private static final int CAMERA_REQUEST = 1888;
private String currentPhotoPath;
private ImageView imageView;
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
imageView = findViewById(R.id.image_view);
dispatchTakePictureIntent();
}
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException e) {
e.printStackTrace();
}
if (photoFile != null) {
Uri photoUri = FileProvider.getUriForFile(this,
"com.example.fileprovider", photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
takePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
startActivityForResult(takePictureIntent, CAMERA_REQUEST);
}
}
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAMERA_REQUEST && resultCode == RESULT_OK) {
// 若指定 EXTRA_OUTPUT,data 可能為 null,直接讀取檔案
Bitmap bitmap = BitmapFactory.decodeFile(currentPhotoPath);
imageView.setImageBitmap(bitmap);
}
}
private File createImageFile() throws IOException {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(imageFileName, ".jpg", storageDir);
currentPhotoPath = image.getAbsolutePath();
return image;
}
}
// 關鍵修正點:
Camera camera = Camera.open();
Camera.Parameters params = camera.getParameters();
// 1. 設定合適的預覽/拍照尺寸 (從支援列表中選擇)
List sizes = params.getSupportedPictureSizes();
Camera.Size bestSize = sizes.get(0); // 簡單取第一個,實際應選最接近螢幕比例
params.setPictureSize(bestSize.width, bestSize.height);
// 2. 對焦模式設為連續對焦 (拍照最穩定)
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
// 3. 關閉閃光燈 (避免干擾)
params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
camera.setParameters(params);
// 4. SurfaceView 預覽就緒後再拍照
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override public void surfaceCreated(SurfaceHolder holder) {
try {
camera.setPreviewDisplay(holder);
camera.startPreview();
// 延遲拍照,讓預覽穩定
new Handler().postDelayed(() -> {
camera.takePicture(null, null, jpegCallback);
}, 500);
} catch (IOException e) { e.printStackTrace(); }
}
// ... 其他回調
});
// 5. 正確處理 jpegCallback
Camera.PictureCallback jpegCallback = (data, camera) -> {
if (data != null && data.length > 0) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(photoFile);
fos.write(data);
fos.close();
// 通知 UI 更新
runOnUiThread(() -> imageView.setImageBitmap(BitmapFactory.decodeByteArray(data, 0, data.length)));
} catch (IOException e) { e.printStackTrace(); }
}
// 重要:拍照後需重新啟動預覽 (若要連拍)
camera.startPreview();
};
// 依賴
implementation "androidx.camera:camera-core:1.3.0"
implementation "androidx.camera:camera-camera2:1.3.0"
implementation "androidx.camera:camera-view:1.3.0"
// 使用
ProcessCameraProvider provider = ProcessCameraProvider.getInstance(this).get();
Preview preview = new Preview.Builder().build();
preview.setSurfaceProvider(viewFinder.getSurfaceProvider());
ImageCapture imageCapture = new ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
.build();
CameraSelector selector = CameraSelector.DEFAULT_BACK_CAMERA;
provider.bindToLifecycle(this, selector, preview, imageCapture);
// 拍照
File photoFile = createImageFile();
OutputFileOptions options = new OutputFileOptions.Builder(photoFile).build();
imageCapture.takePicture(options, ContextCompat.getMainExecutor(this),
new ImageCapture.OnImageSavedCallback() {
@Override public void onImageSaved(@NonNull ImageCapture.OutputFileResults results) {
// 成功
Bitmap bitmap = BitmapFactory.decodeFile(photoFile.getAbsolutePath());
imageView.setImageBitmap(bitmap);
}
@Override public void onError(@NonNull ImageCaptureException exception) {
// 失敗
}
});