admin管理员组文章数量:1302328
I hava an andriod app that uses camera2 api to save images in the gallery it works and saves the images well, but when i take three successive images without closing the app it takes much time to save the third image and i don't want the saving to take more than 5 seconds. public void takePicture() {
try {
CameraManager manager = (CameraManager) getActivity().getSystemService(Context.CAMERA_SERVICE);
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraDevice.getId());
Size[] jpegSizes = Objects.requireNonNull(characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)).getOutputSizes(ImageFormat.JPEG);
int width = 640;
int height = 480;
if (jpegSizes != null && jpegSizes.length > 0) {
width = jpegSizes[0].getWidth();
height = jpegSizes[0].getHeight();
}
ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1);
List<Surface> outputSurfaces = new ArrayList<>(2);
outputSurfaces.add(reader.getSurface());
outputSurfaces.add(new Surface(binding.textUreView.getSurfaceTexture()));
final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(reader.getSurface());
captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
// Orientation
int rotation = getActivity().getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
// Set the zoom level to match the preview
Rect sensorArraySize = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
String zoomLevelString = getString(R.string.ZOOM_LEVEL);
float zoomLevel = Float.parseFloat(zoomLevelString);
assert sensorArraySize != null;
int cropW = (int) (sensorArraySize.width() / zoomLevel);
int cropH = (int) (sensorArraySize.height() / zoomLevel);
int cropX = (sensorArraySize.width() - cropW) / 2;
int cropY = (sensorArraySize.height() - cropH) / 2;
Rect zoomRect = new Rect(cropX, cropY, cropX + cropW, cropY + cropH);
captureBuilder.set(CaptureRequest.SCALER_CROP_REGION, zoomRect);
ImageReader.OnImageAvailableListener readerListener = imageReaderListener -> {
try (Image image = imageReaderListener.acquireLatestImage()) {
if (image == null) {
showUserMessage(getString(R.string.message_image_capture_failed));
return;
}
// Extract image bytes
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
userLocation.getLastLocation(location -> {
// Retrieve location data
double latitude = location.getLatitude();
double longitude = location.getLongitude();
try {
// Save the image with location metadata (if supported by the method)
String savedFileName;
// Save image with location metadata using a newer API for Android R and above
savedFileName = saveImageWithLocation(bytes, latitude, longitude);
// Notify the main activity with the saved image path
cameraViewModel.setImageFinalName(savedFileName);
// Show a message to the user about the successful save operation
showUserMessage(getString(R.string.message_image_save_successful));
} catch (IOException e) {
// Handle exceptions during file saving
showUserMessage(getString(R.string.message_image_save_failed));
cameraViewModel.setCameraException(e);
}
});
} catch (Exception e) {
// Handle any exceptions that occur during image acquisition or processing
showUserMessage(getString(R.string.message_image_processing_error));
cameraViewModel.setCameraException(e);
}
};
reader.setOnImageAvailableListener(readerListener, mBackgroundHandler);
final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
createCameraPreview();
}
};
cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
try {
session.capture(captureBuilder.build(), captureListener, mBackgroundHandler);
}catch (CameraAccessException e) {
// Show a dialog for CameraAccessException
showErrorDialog(getString(R.string.error_title_camera), getString(R.string.camera_access_exception, e.getMessage()));
} catch (IllegalStateException e) {
// Show a dialog for IllegalStateException
showErrorDialog(getString(R.string.error_title_runtime), getString(R.string.camera_runtime_error_illegal_state_exception, e.getMessage()));
}
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
session.close();
}
}, mBackgroundHandler);
} catch (CameraAccessException e) {
throw new RuntimeException(e);
}
}
/**
* Show a message to the user using a Toast or Dialog.
*
* @param message The message to be displayed to the user.
*/
private void showUserMessage(String message) {
if (getActivity() != null) {
Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show();
}
}
/**
* @returnthe image name
*/
@SuppressLint("SimpleDateFormat")
private String generateCapturedImageName() {
Date date = new Date();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd-kk-mm-ss");
String newPicFile = df.format(date);
return userFullName +"_"+ newPicFile + ".jpg";
}
private String saveImageWithLocation(byte[] bytes, double latitude, double longitude) throws IOException {
// Generate a single filename
String fileName = generateCapturedImageName();
// Ensure external directory exists
File directory = ensureDirectoryExists();
// Create the file
File fileFinal = new File(directory, fileName);
// Store the filename and directory in the ViewModel
cameraViewModel.setImageFileName(fileName); // Store the filename
cameraViewModel.setFileDirectory(directory); // Store the directory
// Write the image data to the file
try (OutputStream output = new FileOutputStream(fileFinal)) {
output.write(bytes);
}
// Set EXIF metadata for GPS location
ExifInterface exif = new ExifInterface(fileFinal.getAbsolutePath());
userLocation.setExifGpsData(exif, latitude, longitude);
exif.saveAttributes();
// Notify MediaScanner
MediaScannerConnection.scanFile(
getActivity().getApplicationContext(),
new String[]{fileFinal.getAbsolutePath()},
null,
(path, uri) -> Log.d(TAG, getString(R.string.Image_scanned_into_gallery) + path)
);
Log.d("FileDebug", "File created at: " + fileFinal.getAbsolutePath());
return fileFinal.getAbsolutePath();
}
I tried to create different threads and change the image reader maxImages from 2 to 5 but it didn't work. I also tried to take to clean the image buffer but didn't find the solution.
I hava an andriod app that uses camera2 api to save images in the gallery it works and saves the images well, but when i take three successive images without closing the app it takes much time to save the third image and i don't want the saving to take more than 5 seconds. public void takePicture() {
try {
CameraManager manager = (CameraManager) getActivity().getSystemService(Context.CAMERA_SERVICE);
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraDevice.getId());
Size[] jpegSizes = Objects.requireNonNull(characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)).getOutputSizes(ImageFormat.JPEG);
int width = 640;
int height = 480;
if (jpegSizes != null && jpegSizes.length > 0) {
width = jpegSizes[0].getWidth();
height = jpegSizes[0].getHeight();
}
ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1);
List<Surface> outputSurfaces = new ArrayList<>(2);
outputSurfaces.add(reader.getSurface());
outputSurfaces.add(new Surface(binding.textUreView.getSurfaceTexture()));
final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(reader.getSurface());
captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
// Orientation
int rotation = getActivity().getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
// Set the zoom level to match the preview
Rect sensorArraySize = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
String zoomLevelString = getString(R.string.ZOOM_LEVEL);
float zoomLevel = Float.parseFloat(zoomLevelString);
assert sensorArraySize != null;
int cropW = (int) (sensorArraySize.width() / zoomLevel);
int cropH = (int) (sensorArraySize.height() / zoomLevel);
int cropX = (sensorArraySize.width() - cropW) / 2;
int cropY = (sensorArraySize.height() - cropH) / 2;
Rect zoomRect = new Rect(cropX, cropY, cropX + cropW, cropY + cropH);
captureBuilder.set(CaptureRequest.SCALER_CROP_REGION, zoomRect);
ImageReader.OnImageAvailableListener readerListener = imageReaderListener -> {
try (Image image = imageReaderListener.acquireLatestImage()) {
if (image == null) {
showUserMessage(getString(R.string.message_image_capture_failed));
return;
}
// Extract image bytes
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
userLocation.getLastLocation(location -> {
// Retrieve location data
double latitude = location.getLatitude();
double longitude = location.getLongitude();
try {
// Save the image with location metadata (if supported by the method)
String savedFileName;
// Save image with location metadata using a newer API for Android R and above
savedFileName = saveImageWithLocation(bytes, latitude, longitude);
// Notify the main activity with the saved image path
cameraViewModel.setImageFinalName(savedFileName);
// Show a message to the user about the successful save operation
showUserMessage(getString(R.string.message_image_save_successful));
} catch (IOException e) {
// Handle exceptions during file saving
showUserMessage(getString(R.string.message_image_save_failed));
cameraViewModel.setCameraException(e);
}
});
} catch (Exception e) {
// Handle any exceptions that occur during image acquisition or processing
showUserMessage(getString(R.string.message_image_processing_error));
cameraViewModel.setCameraException(e);
}
};
reader.setOnImageAvailableListener(readerListener, mBackgroundHandler);
final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
createCameraPreview();
}
};
cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
try {
session.capture(captureBuilder.build(), captureListener, mBackgroundHandler);
}catch (CameraAccessException e) {
// Show a dialog for CameraAccessException
showErrorDialog(getString(R.string.error_title_camera), getString(R.string.camera_access_exception, e.getMessage()));
} catch (IllegalStateException e) {
// Show a dialog for IllegalStateException
showErrorDialog(getString(R.string.error_title_runtime), getString(R.string.camera_runtime_error_illegal_state_exception, e.getMessage()));
}
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
session.close();
}
}, mBackgroundHandler);
} catch (CameraAccessException e) {
throw new RuntimeException(e);
}
}
/**
* Show a message to the user using a Toast or Dialog.
*
* @param message The message to be displayed to the user.
*/
private void showUserMessage(String message) {
if (getActivity() != null) {
Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show();
}
}
/**
* @returnthe image name
*/
@SuppressLint("SimpleDateFormat")
private String generateCapturedImageName() {
Date date = new Date();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd-kk-mm-ss");
String newPicFile = df.format(date);
return userFullName +"_"+ newPicFile + ".jpg";
}
private String saveImageWithLocation(byte[] bytes, double latitude, double longitude) throws IOException {
// Generate a single filename
String fileName = generateCapturedImageName();
// Ensure external directory exists
File directory = ensureDirectoryExists();
// Create the file
File fileFinal = new File(directory, fileName);
// Store the filename and directory in the ViewModel
cameraViewModel.setImageFileName(fileName); // Store the filename
cameraViewModel.setFileDirectory(directory); // Store the directory
// Write the image data to the file
try (OutputStream output = new FileOutputStream(fileFinal)) {
output.write(bytes);
}
// Set EXIF metadata for GPS location
ExifInterface exif = new ExifInterface(fileFinal.getAbsolutePath());
userLocation.setExifGpsData(exif, latitude, longitude);
exif.saveAttributes();
// Notify MediaScanner
MediaScannerConnection.scanFile(
getActivity().getApplicationContext(),
new String[]{fileFinal.getAbsolutePath()},
null,
(path, uri) -> Log.d(TAG, getString(R.string.Image_scanned_into_gallery) + path)
);
Log.d("FileDebug", "File created at: " + fileFinal.getAbsolutePath());
return fileFinal.getAbsolutePath();
}
I tried to create different threads and change the image reader maxImages from 2 to 5 but it didn't work. I also tried to take to clean the image buffer but didn't find the solution.
Share asked Feb 11 at 6:39 LuaiLuai 11 bronze badge1 Answer
Reset to default 0The delay in saving the third image is due to location fetching latency. The first and second images used cached location data, while the third might be triggering a fresh location request, which can take longer.
Location API Delay: The fusedLocationClient.getCurrentLocation(...) method can take longer if a fresh GPS fix is required. Slow Network: If your phone is relying on network-based location rather than GPS, fetching new location data may be slow. Blocked UI/Main Thread: If location fetching or saving the image runs on the main thread, it can slow down. Power Saving Mode: Some Android devices limit location updates in low-power states. So Instead of calling getCurrentLocation() every time, I used getLastLocation() first, which is much faster because it returns the last known location without waiting for a new GPS fix.
版权声明:本文标题:android - Saving images to gallery in andriod studio delays after the third successive image - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741675130a2391835.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论