#java #android #android-camerax
#java #Android #android-camerax
Вопрос:
Я пытаюсь реализовать захват изображения в соответствии с https://developer.android.com/training/camerax/take-photo , Я запускаю свое устройство на Temi Robot, предварительный просмотр, кажется, работает нормально, но я сталкиваюсь с этой ошибкой, и обратный вызов не выполняется, когда я пытаюсь захватить изображение.
Это фрагмент, в котором вызывается код camerax
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewModel = new ViewModelProvider(getActivity()).get(GlobalViewModel.class);
cameraProviderFuture = ProcessCameraProvider.getInstance(getContext());
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.patrol_fragment, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
previewView = view.findViewById(R.id.previewView);
cameraProviderFuture.addListener(() -> {
try {
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
bindPreview(cameraProvider, view);
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "CameraProvider initialization error: " e.toString());
}
}, ContextCompat.getMainExecutor(getContext()));
Just for testing
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
takePicture();
}
}, 10000);
}
private void bindPreview(ProcessCameraProvider cameraProvider, View view) {
Preview preview = new Preview.Builder().build();
CameraSelector cameraSelector = new CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_FRONT)
.build();
preview.setSurfaceProvider(previewView.getSurfaceProvider());
imageCapture = new ImageCapture.Builder()
.setTargetRotation(view.getDisplay().getRotation())
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
.build();
Camera camera = cameraProvider.bindToLifecycle(getActivity(), cameraSelector, imageCapture,
preview);
takePicture();
}
private void takePicture() {
File mediaFile = getMediaFile();
ImageCapture.OutputFileOptions outputFileOptions =
new ImageCapture.OutputFileOptions.Builder(mediaFile).build();
imageCapture.takePicture(outputFileOptions, viewModel.getExecutorService(),
new ImageCapture.OnImageSavedCallback() {
@Override
public void onImageSaved(ImageCapture.OutputFileResults outputFileResults) {
// insert your code here.
Log.i(TAG, "Capture success!");
}
@Override
public void onError(ImageCaptureException error) {
// insert your code here.
Log.e(TAG, "Capture failed :( " error.toString());
}
}
);
}
private File getMediaFile() {
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "TemiPatrol");
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
Log.d(TAG, "failed to create directory");
return null;
}
}
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
return new File(mediaStorageDir.getPath() File.separator
"IMG_" timeStamp ".jpg");
}
private void sendImageToServer(JSONObject requestJson) {
// for testing
viewModel.getExecutorService().execute(() -> {
JsonPostman postman = new JsonPostman(getActivity());
postman.postRequest(requestJson);
});
}
}
Ответ №1:
Вы не можете делать снимки, потому ImageCapture
что не был настроен правильно, вы не привязываете его при вызове ProcessCameraProvider.bindToLifecycle()
. Вы должны написать что-то вроде этого:
Preview preview = ...;
preview.setSurfaceProvider(...);
ImageCapture imageCapture = ...;
// bind both preview and imageCapture
cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview, imageCapture);
Это позволит (должно) разрешить takePicture()
успешные вызовы.
У меня есть еще 2 комментария к вашему коду.
- Код, который вы добавили в целях тестирования (где вы планируете захват изображения через 10 секунд), должен выполняться только в том случае, если настройка камеры работает. Вы могли бы запустить его после вызова
bindToLifecycle()
, например. - Привязка вариантов использования к жизненному циклу действия фрагмента, вероятно, не очень хорошая идея. Владелец жизненного цикла в
bindToLifecycle(LifecycleOwner, ...)
управляет открытием и закрытием камеры, поэтому обычно требуется, чтобы камера запускалась при запуске фрагмента или его просмотра, и останавливалась при остановке фрагмента или его просмотра. Поскольку вы отображаете предварительный просмотр, вы можете привязать открытие / закрытие камеры к жизненному циклу просмотра фрагмента, чтобы вы могли писать:
cameraProvider.bindToLifecycle(getViewLifecycleOwner(), cameraSelector, preview, imageCapture);
Комментарии:
1. Я думаю, вы пропустили ту часть, где я привязал ImageCapture, поскольку он был отключен экраном, но ImageCapture уже был включен в
bindToLifecycle
метод, который был вызван вbindPreview
методе вonViewCreated
Я изменил владельца жизненного цикла, как вы предложили.2. Ах, мой плохой, я пропустил ту часть, где вы привязываете вариант использования захвата изображения. Можете ли вы воспроизвести эту проблему на других устройствах? И сталкиваетесь ли вы с этой проблемой на роботе Temi, в котором запущены другие приложения для камеры, например, пример приложения camera2.
3. Изначально я использовал устаревшую библиотеку камер, предварительный просмотр и захват изображений работали нормально, но возникла проблема, из-за которой захваченные изображения поворачивались на 180 градусов, и я не мог найти способ решить эту проблему, поэтому я решил попробовать camerax. Мне еще предстоит попытаться запустить приложение на других устройствах / попробовать пример приложения camera2, но пока предварительный просмотр camerax работает нормально.
4. Обновление: с тех пор я протестировал CameraXBasic и Camera2Basic из github.com/android/camera-samples и оба, начиная с работы над роботом Temi, оба, кажется, работают!