Android CameraX - 预览黑色/片段恢复后不可见

问题描述 投票:0回答:1

我正在使用CameraX,预览、图像和视频捕获。我创建了一个片段类,它使用绑定到生命周期来避免所有手动相机预览状态管理等(按照 Google 的建议)。问题是,有时如果我将应用程序置于后台然后置于前台,相机预览为黑色并且不显示预览。除了重新创建片段之外,没有其他方法可以恢复它。有什么提示我可能做错了什么吗?

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.util.Size;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.camera.core.AspectRatio;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.ImageCaptureException;
import androidx.camera.core.Preview;
import androidx.camera.core.UseCaseGroup;
import androidx.camera.core.VideoCapture;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import com.google.common.util.concurrent.ListenableFuture;
import com.google.mlkit.vision.face.Face;
import 

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class CameraViewFragment extends BaseFragment {

    private static final int REQUEST_CAMERA_PERMISSIONS = 100;
    private CameraViewFragmentListener listener;

    private final Executor executor = Executors.newSingleThreadExecutor();
    private Camera camera;
    private Handler handler = new Handler();
    private boolean isRecording;
    private Preview preview;
    private ImageCapture imageCapture;
    private VideoCapture videoCapture;
    private ImageAnalysis imageAnalysis;
    private FaceDetector faceDetector;

    public interface CameraViewFragmentListener {
        void onCameraPictureTaken(byte[] buffer);

        void onCameraPermissionsRejected();

        void onCameraVideoRecorded(Uri file);

        void onCameraVideoRecordError(Throwable ex);

        void onCameraFacesDetect(List<Face> faces);

        void onCameraFacesDetectError(Exception e);

        enum CameraFeature {
            PREVIEW,
            IMAGE_CAPTURE,
            VIDEO_CAPTURE,
            FACE_DETECTION
        }
        Set<CameraFeature> cameraGetRequestedFeatures();
    }

    private FragmentCameraViewBinding binding;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        binding = FragmentCameraViewBinding.inflate(inflater, container, false);
        return binding.getRoot();
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        int rc = ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA);
        if (rc == PackageManager.PERMISSION_GRANTED) {
            startCamera();
        } else {
            requestCameraPermission();
        }
    }

    private void requestCameraPermission() {
        requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSIONS);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_CAMERA_PERMISSIONS) {
            if (permissions.length == 1 && permissions[0].equals(Manifest.permission.CAMERA) && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Logger.log(Logger.info, "[VRM] Camera permission granted.");
                startCamera();//createCameraSource();
            } else {
                Logger.log(Logger.error, "[VRM] Camera permission NOT granted.");
                if (listener != null) {
                    listener.onCameraPermissionsRejected();
                }
                requestCameraPermission();
            }
        }
    }

    /**
     * Restarts the camera.
     */
    @Override
    public void onResume() {
        super.onResume();

        //startCamera();
    }

    /**
     * Stops the camera.
     */
    @Override
    public void onPause() {
        super.onPause();

    }

    /**
     * Releases the resources associated with the camera source, the associated detector, and the
     * rest of the processing pipeline.
     */
    @Override
    public void onDestroy() {
        super.onDestroy();

    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof CameraViewFragmentListener) {
            listener = (CameraViewFragmentListener) context;
        } else if (getParentFragment() instanceof CameraViewFragmentListener) {
            listener = (CameraViewFragmentListener) getParentFragment();
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        listener = null;
    }


    private void startCamera() {
        final ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext());
        cameraProviderFuture.addListener(() -> {
            try {
                ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
                Set<CameraViewFragmentListener.CameraFeature> features = listener.cameraGetRequestedFeatures();
                bindUseCases(cameraProvider, features);
            } catch (ExecutionException | InterruptedException e) {
                // No errors need to be handled for this Future.
                // This should never be reached.
                Logger.log(Logger.error, "Exception while initializing CameraX: {}", e);
            }
        }, ContextCompat.getMainExecutor(requireContext()));
    }

    void bindUseCases(@NonNull ProcessCameraProvider cameraProvider, Set<CameraViewFragmentListener.CameraFeature> features) {
        cameraProvider.unbindAll();
        final CameraSelector cameraSelector = new CameraSelector.Builder()
                .requireLensFacing(CameraSelector.LENS_FACING_FRONT)
                .build();
        final WindowManager wm = (WindowManager) requireContext().getSystemService(Context.WINDOW_SERVICE);
        final UseCaseGroup.Builder useCaseGroupBuilder = new UseCaseGroup.Builder();
        if (features.contains(CameraViewFragmentListener.CameraFeature.PREVIEW)) {
            preview = new Preview.Builder()
                    .setTargetAspectRatio(AspectRatio.RATIO_4_3)
                    //.setTargetResolution(new Size(480, 640))
                    .build();
            binding.preview.setScaleType(PreviewView.ScaleType.FILL_CENTER);
            preview.setSurfaceProvider(binding.preview.getSurfaceProvider());
            useCaseGroupBuilder.addUseCase(preview);
        } else {
            preview = null;
        }

        if (features.contains(CameraViewFragmentListener.CameraFeature.IMAGE_CAPTURE)) {
            imageCapture = new ImageCapture.Builder()
                    .setCameraSelector(cameraSelector)
                    .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
                    //.setTargetAspectRatio(AspectRatio.RATIO_4_3)
                    .setTargetResolution(new Size(480, 640))
                    .setTargetRotation(wm.getDefaultDisplay().getRotation())
                    .build();
            useCaseGroupBuilder.addUseCase(imageCapture);
        } else {
            imageCapture = null;
        }

        if (features.contains(CameraViewFragmentListener.CameraFeature.VIDEO_CAPTURE)) {
            videoCapture = new VideoCapture.Builder()
                    .setCameraSelector(cameraSelector)
                    //.setTargetResolution(new Size(480, 640))
                    .setBitRate(1000)
                    .setTargetAspectRatio(AspectRatio.RATIO_4_3)
                    .setTargetRotation(wm.getDefaultDisplay().getRotation())
                    .build();
            useCaseGroupBuilder.addUseCase(videoCapture);
        } else {
            videoCapture = null;
        }

        if (features.contains(CameraViewFragmentListener.CameraFeature.FACE_DETECTION)) {
            imageAnalysis = new ImageAnalysis.Builder()
                    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                    .build();

            faceDetector = new FaceDetector(new FaceDetector.FaceDetectorListener() {
                @Override
                public void onFaceDetectSuccess(List<Face> faces) {
                    if (listener!=null)
                        listener.onCameraFacesDetect(faces);
                }

                @Override
                public void onFaceDetectError(Exception e) {
                    if (listener!=null)
                        listener.onCameraFacesDetectError(e);
                }
            });
            imageAnalysis.setAnalyzer(executor, faceDetector.createAnalyzer());
            useCaseGroupBuilder.addUseCase(imageAnalysis);
        } else {
            imageAnalysis = null;
        }
        camera = cameraProvider.bindToLifecycle(this, cameraSelector, useCaseGroupBuilder.build());
    }


    public void requestTakePicture() {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(bos).build();
        imageCapture.takePicture(outputFileOptions, executor, new ImageCapture.OnImageSavedCallback() {
            @Override
            public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
                handler.post(() -> {
                    //Toast.makeText(MainActivity.this, "Image Saved successfully", Toast.LENGTH_SHORT).show();
                    if (listener != null) {
                        listener.onCameraPictureTaken(bos.toByteArray());
                    }
                });
            }

            @Override
            public void onError(@NonNull ImageCaptureException error) {
                error.printStackTrace();
            }
        });
    }

    public void startVideoRecording(File file) {
        VideoCapture.OutputFileOptions outputFileOptions = new VideoCapture.OutputFileOptions
                .Builder(file)
                .build();
        videoCapture.startRecording(outputFileOptions, executor, new VideoCapture.OnVideoSavedCallback() {
            @Override
            public void onVideoSaved(@NonNull VideoCapture.OutputFileResults outputFileResults) {
                handler.post(() -> {
                    isRecording = false;
                    //Toast.makeText(MainActivity.this, "Image Saved successfully", Toast.LENGTH_SHORT).show();
                    if (listener != null) {
                        listener.onCameraVideoRecorded(outputFileResults.getSavedUri());
                    }
                });
            }

            @Override
            public void onError(int videoCaptureError, @NonNull String message, @Nullable Throwable cause) {
                isRecording = false;
                if (listener != null) {
                    listener.onCameraVideoRecordError(cause);
                }
            }
        });
        isRecording = true;
    }

    public void stopVideoRecording() {
        videoCapture.stopRecording();
        isRecording = false;
    }

    public boolean isRecording() {
        return isRecording;
    }
}
android camera android-camerax
1个回答
0
投票

这里提出了一个问题: https://issuetracker.google.com/issues/147354615

使用建议的解决方案,您应该在 onResume() 中重新分配预览,例如:

private void setPreview() {
    if (getLifecycle().getCurrentState() != Lifecycle.State.DESTROYED) {
        Preview preview = new Preview.Builder().setTargetAspectRatio(AspectRatio.RATIO_4_3).build();
        CameraSelector cameraSelector = new CameraSelector.Builder()
                .requireLensFacing(CameraSelector.LENS_FACING_BACK).build();
        preview.setSurfaceProvider(previewView.getSurfaceProvider());
        cam = cameraProvider.bindToLifecycle(StockOCRFragment.this, cameraSelector, imageCapture, preview);
    }
}

@Override
public void onPause() {
    super.onPause();
    stopped = true;
    if (cameraProvider != null) {
        cameraProvider.unbindAll();
    }
}

@Override
public void onResume() {
    super.onResume();
    if (stopped && cameraProvider != null) {
        setPreview();
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.