Camera2 API 和 java.lang.IllegalStateException

Posted

技术标签:

【中文标题】Camera2 API 和 java.lang.IllegalStateException【英文标题】:Camera2 API and java.lang.IllegalStateException 【发布时间】:2017-08-02 14:36:33 【问题描述】:

我正在创建一个支持已弃用和新相机 API 的应用。第一个就像一个魅力,但我正在努力使用 Camera2 API。在测试阶段,我注意到奇怪的行为。测试设备为三星 Galaxy S5 安卓 6.0.1 当我按下电源/结束键然后返回应用程序时,这就是我得到的(并非每次都发生):

03-12 16:14:32.704 24117-24117/pl.tripper.tripper E/MainActivity: onPause
03-12 16:14:32.774 24117-24128/pl.tripper.tripper E/BufferQueueProducer: [SurfaceTexture-1-24117-2] dequeueBuffer: BufferQueue has been abandoned
03-12 16:14:32.784 24117-24145/pl.tripper.tripper E/BufferQueueProducer: [SurfaceTexture-1-24117-2] queueBuffer: BufferQueue has been abandoned
03-12 16:14:33.044 24117-24128/pl.tripper.tripper E/BufferQueueProducer: [SurfaceTexture-1-24117-2] cancelBuffer: BufferQueue has been abandoned
03-12 16:14:33.044 24117-24145/pl.tripper.tripper E/BufferQueueProducer: [SurfaceTexture-1-24117-2] cancelBuffer: BufferQueue has been abandoned
03-12 16:14:33.054 24117-24129/pl.tripper.tripper E/BufferQueueProducer: [SurfaceTexture-1-24117-2] cancelBuffer: BufferQueue has been abandoned
03-12 16:14:33.054 24117-24128/pl.tripper.tripper E/BufferQueueProducer: [SurfaceTexture-1-24117-2] cancelBuffer: BufferQueue has been abandoned
03-12 16:14:33.264 24117-24117/pl.tripper.tripper E/CameraNewApi: cameraComponentsReleased
03-12 16:14:33.264 24117-24117/pl.tripper.tripper E/CameraNewApi: StopCameraThread
03-12 16:14:33.264 24117-24117/pl.tripper.tripper E/CameraApiManager: cameraPreviewRemoved
03-12 16:14:33.264 24117-24117/pl.tripper.tripper E/CameraNewApi: onSurfaceDestroyed
03-12 16:14:33.634 24117-24117/pl.tripper.tripper E/MainActivity: onCreate
03-12 16:14:33.634 24117-24117/pl.tripper.tripper E/MainActivity: onResume
03-12 16:14:33.634 24117-24117/pl.tripper.tripper E/CameraNewApi: startCameraThread
03-12 16:14:33.634 24117-24117/pl.tripper.tripper E/CameraApiManager: cameraPreviewCreated
03-12 16:14:33.644 24117-24117/pl.tripper.tripper E/CameraNewApi: initCamera
03-12 16:14:33.674 24117-24117/pl.tripper.tripper E/CameraNewApi: onSurfaceCreated
03-12 16:14:33.674 24117-24117/pl.tripper.tripper E/CameraNewApi: openCamera
03-12 16:14:33.914 24117-24117/pl.tripper.tripper E/CameraNewApi: onSurfaceChanged
03-12 16:14:33.914 24117-25053/pl.tripper.tripper E/CameraNewApi: onOpened
03-12 16:14:33.914 24117-25053/pl.tripper.tripper E/CameraNewApi: createCameraPreview
03-12 16:14:33.934 24117-24117/pl.tripper.tripper E/MainActivity: onPause
03-12 16:14:34.174 24117-24117/pl.tripper.tripper E/CameraNewApi: cameraComponentsReleased
03-12 16:14:34.174 24117-25053/pl.tripper.tripper E/CameraNewApi: onConfigured
03-12 16:14:34.174 24117-24117/pl.tripper.tripper E/CameraNewApi: StopCameraThread
03-12 16:14:34.174 24117-24117/pl.tripper.tripper E/CameraApiManager: cameraPreviewRemoved
03-12 16:14:34.184 24117-24117/pl.tripper.tripper E/CameraNewApi: onSurfaceDestroyed
03-12 16:14:34.914 24117-24117/pl.tripper.tripper E/MainActivity: onResume
03-12 16:14:34.914 24117-24117/pl.tripper.tripper E/CameraNewApi: startCameraThread
03-12 16:14:34.924 24117-24117/pl.tripper.tripper E/CameraApiManager: cameraPreviewCreated
03-12 16:14:34.924 24117-24117/pl.tripper.tripper E/CameraNewApi: initCamera
03-12 16:14:34.964 24117-24117/pl.tripper.tripper E/CameraNewApi: onSurfaceCreated
03-12 16:14:34.964 24117-24117/pl.tripper.tripper E/CameraNewApi: openCamera
03-12 16:14:35.294 24117-24117/pl.tripper.tripper E/CameraNewApi: onSurfaceChanged
03-12 16:14:35.294 24117-25121/pl.tripper.tripper E/CameraNewApi: onOpened
03-12 16:14:35.294 24117-25121/pl.tripper.tripper E/CameraNewApi: createCameraPreview
03-12 16:14:35.354 24117-24117/pl.tripper.tripper E/CameraNewApi: onSurfaceChanged
03-12 16:14:35.374 24117-24117/pl.tripper.tripper E/MainActivity: onPause
03-12 16:14:35.384 24117-25121/pl.tripper.tripper E/CameraNewApi: onConfigured
03-12 16:14:35.594 24117-24117/pl.tripper.tripper E/CameraNewApi: cameraComponentsReleased
03-12 16:14:35.594 24117-25121/pl.tripper.tripper E/CameraNewApi: Session was closed or camera device has been closed. 
                                                                  java.lang.IllegalStateException: CameraDevice was already closed
                                                                      at android.hardware.camera2.impl.CameraDeviceImpl.checkIfCameraClosedOrInError(CameraDeviceImpl.java:1997)
                                                                      at android.hardware.camera2.impl.CameraDeviceImpl.submitCaptureRequest(CameraDeviceImpl.java:844)
                                                                      at android.hardware.camera2.impl.CameraDeviceImpl.setRepeatingRequest(CameraDeviceImpl.java:899)
                                                                      at android.hardware.camera2.impl.CameraCaptureSessionImpl.setRepeatingRequest(CameraCaptureSessionImpl.java:236)
                                                                      at pl.tripper.tripper.camera.CameraNewApi$2.onConfigured(CameraNewApi.java:107)
                                                                      at java.lang.reflect.Method.invoke(Native Method)
                                                                      at android.hardware.camera2.dispatch.InvokeDispatcher.dispatch(InvokeDispatcher.java:39)
                                                                      at android.hardware.camera2.dispatch.HandlerDispatcher$1.run(HandlerDispatcher.java:65)
                                                                      at android.os.Handler.handleCallback(Handler.java:739)
                                                                      at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                      at android.os.Looper.loop(Looper.java:158)
                                                                      at android.os.HandlerThread.run(HandlerThread.java:61)
03-12 16:14:35.594 24117-24117/pl.tripper.tripper E/CameraNewApi: StopCameraThread
03-12 16:14:35.594 24117-25121/pl.tripper.tripper E/CameraNewApi: cameraComponentsReleased
03-12 16:14:35.594 24117-24117/pl.tripper.tripper E/CameraApiManager: cameraPreviewRemoved
03-12 16:14:35.604 24117-24117/pl.tripper.tripper E/CameraNewApi: onSurfaceDestroyed
03-12 16:14:35.644 24117-24117/pl.tripper.tripper E/MainActivity: onCreate
03-12 16:14:35.654 24117-24117/pl.tripper.tripper E/MainActivity: onResume
03-12 16:14:35.654 24117-24117/pl.tripper.tripper E/CameraNewApi: startCameraThread
03-12 16:14:35.654 24117-24117/pl.tripper.tripper E/CameraApiManager: cameraPreviewCreated
03-12 16:14:35.654 24117-24117/pl.tripper.tripper E/CameraNewApi: initCamera
03-12 16:14:35.694 24117-24117/pl.tripper.tripper E/CameraNewApi: onSurfaceCreated
03-12 16:14:35.694 24117-24117/pl.tripper.tripper E/CameraNewApi: openCamera
03-12 16:14:35.934 24117-24117/pl.tripper.tripper E/CameraNewApi: onSurfaceChanged
03-12 16:14:35.934 24117-25184/pl.tripper.tripper E/CameraNewApi: onOpened
03-12 16:14:35.934 24117-25184/pl.tripper.tripper E/CameraNewApi: createCameraPreview
03-12 16:14:35.944 24117-24117/pl.tripper.tripper E/ViewRootImpl: sendUserActionEvent() mView == null
03-12 16:14:35.944 24117-24117/pl.tripper.tripper E/ViewRootImpl: sendUserActionEvent() mView == null
03-12 16:14:35.994 24117-25184/pl.tripper.tripper E/CameraNewApi: onConfigured

在调用方法时添加了一些错误日志。我知道当会话仍在运行时 cameraDevice 为空,但我不知道如何修复它。发生java.lang.IllegalStateException 错误后,相机继续工作。第二个问题是BufferQueueProducer 错误,但我不知道这是从哪里来的。

03-12 15:47:40.244 30720-30731/pl.tripper.tripper E/BufferQueueProducer: [SurfaceTexture-1-30720-1] dequeueBuffer: BufferQueue has been abandoned
03-12 15:47:40.244 30720-30751/pl.tripper.tripper E/BufferQueueProducer: [SurfaceTexture-1-30720-1] queueBuffer: BufferQueue has been abandoned
03-12 15:47:40.524 30720-30731/pl.tripper.tripper E/BufferQueueProducer: [SurfaceTexture-1-30720-1] cancelBuffer: BufferQueue has been abandoned
03-12 15:47:40.524 30720-30751/pl.tripper.tripper E/BufferQueueProducer: [SurfaceTexture-1-30720-1] cancelBuffer: BufferQueue has been abandoned
03-12 15:47:40.524 30720-30732/pl.tripper.tripper E/BufferQueueProducer: [SurfaceTexture-1-30720-1] cancelBuffer: BufferQueue has been abandoned
03-12 15:47:40.524 30720-30731/pl.tripper.tripper E/BufferQueueProducer: [SurfaceTexture-1-30720-1] cancelBuffer: BufferQueue has been abandoned

这是我的代码:

MainActivity.class

@Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        Log.e(TAG, "onCreate");
        isImmersiveAvailable();
        cameraApiManager = new CameraApiManager(this, this);
    

    @Override
    protected void onResume() 
        super.onResume();

        Log.e(TAG, "onResume");
       cameraApiManager.createCamera();

    

    @Override
    protected void onPause() 
        super.onPause();

        Log.e(TAG, "onPause");
        cameraApiManager.releaseCameraAndPreview();
    

CameraApiManager.class

public class CameraApiManager implements CameraUtility.cameraOpenedListener 

    private static final String TAG = "CameraApiManager";

    private final WeakReference<MainActivity> mainActivity;
    private Context context;

    private CameraSourceApi cameraSourceApi;
    private CameraPreview cameraPreview;

    public CameraApiManager(Context context, MainActivity mainActivity)

        this.mainActivity= new WeakReference<>(mainActivity);

        cameraSourceApi = new CameraSourceApi<>(new CameraNewApi(context));
        this.context = context;
    

    private boolean cameraProgressBarEnable()
        return context.getResources().getBoolean(R.bool.camera_progress_bar_enable);
    

    private void setCameraProgressBarVisibility(final int visibility )
        final MainActivity mainActivity = this.mainActivity.get();
        if(mainActivity!= null)
            // UI/Main Thread
            if(Looper.myLooper() == Looper.getMainLooper())
                ProgressBar cameraProgressBar = (ProgressBar) mainActivity.findViewById(R.id.camera_progress_bar);
                cameraProgressBar.setVisibility(visibility);
             else 
                mainActivity.runOnUiThread(new Runnable() 
                    @Override
                    public void run() 
                        ProgressBar cameraProgressBar = (ProgressBar) mainActivity.findViewById(R.id.camera_progress_bar);
                        cameraProgressBar.setVisibility(visibility);
                    
                );
            
        
    

    private void showCameraOpenErrorToast()
        Toast.makeText(context, context.getResources().getString(R.string.camera_open_error_toast), Toast.LENGTH_LONG).show();
    

    private boolean cameraPermissionGranted() 
        return ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED;
    

    public void createCamera()
        if(cameraPermissionGranted())
            if(cameraProgressBarEnable())
                setCameraProgressBarVisibility(View.VISIBLE);
            
            cameraSourceApi.createCamera(this);
        
    

    public void releaseCameraAndPreview()
        if(cameraPermissionGranted())
            cameraSourceApi.releaseCamera();
            removeCameraPreview();
        
    

    @Override
    public void onCameraOpened(boolean succeeded, boolean addPreview, boolean progressBar) 
         if(addPreview) 
             if (cameraPreview == null) 
                 Log.e(TAG, "cameraPreviewCreated");
                 cameraPreview = new CameraPreview(context, cameraSourceApi);
                 addCameraPreview();
             
         
         if(!progressBar)
             if(cameraProgressBarEnable())
                 setCameraProgressBarVisibility(View.GONE);
             
         
         if(!succeeded)
             showCameraOpenErrorToast();
         
    

    private void addCameraPreview()
        MainActivity mainActivity = this.mainActivity.get();
        if(mainActivity != null && cameraPreview != null)
            FrameLayout preview = (FrameLayout) mainActivity.findViewById(R.id.camera_preview);
            preview.addView(cameraPreview);
        
    

    private void removeCameraPreview()
        MainActivity mainActivity = this.mainActivity.get();
        if(mainActivity!= null && cameraPreview != null)
            Log.e(TAG, "cameraPreviewRemoved");
            FrameLayout preview = (FrameLayout) mainActivity.findViewById(R.id.camera_preview);
            preview.removeView(cameraPreview);
            cameraPreview = null;
        
    

     class CameraSourceApi<T extends CameraUtility> implements CameraUtility

        private T camera;

        CameraSourceApi(T camera)
            this.camera = camera;
        

        @Override
        public void createCamera(CameraUtility.cameraOpenedListener cameraOpenedListener) 
            camera.createCamera(cameraOpenedListener);
        

        @Override
        public void releaseCamera() 
            camera.releaseCamera();
        

        @Override
        public void onSurfaceCreated(SurfaceHolder surfaceHolder) 
            camera.onSurfaceCreated(surfaceHolder);
        

        @Override
        public void onSurfaceChanged(SurfaceHolder surfaceHolder, int width, int height) 
            camera.onSurfaceChanged(surfaceHolder, width, height);
        

         @Override
         public void onSurfaceDestroyed(SurfaceHolder surfaceHolder) 
             camera.onSurfaceDestroyed(surfaceHolder);
         
     

CameraNewApi.class

@TargetApi(21)
class CameraNewApi implements CameraUtility 

    private static final String TAG = "CameraNewApi";

    private Semaphore cameraOpenCloseLock = new Semaphore(1);

    private CameraUtility.cameraOpenedListener cameraOpenedListener;

    private Context context;

    private Handler backgroundHandler;
    private HandlerThread backgroundThread;

    private SurfaceHolder surfaceHolder;

    private String backFacingCameraId;
    private CaptureRequest.Builder captureRequestBuilder;
    private CameraDevice cameraDevice;
    private CameraCaptureSession cameraCaptureSessions;

    CameraNewApi(Context context)
        this.context = context;
    


    private final CameraDevice.StateCallback cameraDeviceStateCallback = new CameraDevice.StateCallback() 
        @Override
        public void onOpened(@NonNull CameraDevice camera) 
            Log.e(TAG, "onOpened");
            cameraOpenCloseLock.release();
            cameraDevice = camera;
            if(surfaceHolder != null)
                createCameraPreview();
             else 
                releaseCameraComponents();
            
        

        @Override
        public void onDisconnected(@NonNull CameraDevice camera) 
            Log.d(TAG, "deviceCallback.onDisconnected() start");
            Log.e(TAG, "onDisconnected");
            if(cameraOpenedListener != null) 
                cameraOpenedListener.onCameraOpened(false, false, false);
            
            cameraOpenCloseLock.release();
            camera.close();
            cameraDevice = null;
        

        @Override
        public void onError(@NonNull CameraDevice camera, int error) 
            Log.e(TAG, "onError");
            Log.d(TAG, "deviceCallback.onError() start");
            if(cameraOpenedListener != null) 
                cameraOpenedListener.onCameraOpened(false, false, false);
            
            cameraOpenCloseLock.release();
            camera.close();
            cameraDevice = null;
        
    ;

    private final CameraCaptureSession.StateCallback captureSessionStateCallback = new CameraCaptureSession.StateCallback() 
        @Override
        public void onConfigured(@NonNull CameraCaptureSession session) 
            Log.e(TAG, "onConfigured");
            if(cameraDevice != null)
                cameraCaptureSessions = session;
                captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
                try 
                    if(cameraOpenedListener != null) 
                        cameraOpenedListener.onCameraOpened(true, false, false);
                    
                    session.setRepeatingRequest(captureRequestBuilder.build(), null, backgroundHandler);
                 catch (CameraAccessException e) 
                    Log.e(TAG, "Camera has been disconnected", e);
                 catch (IllegalStateException e)
                    Log.e(TAG, "Session was closed or camera device has been closed. ", e);
                    releaseCameraComponents();
                
            
        

        @Override
        public void onConfigureFailed(@NonNull CameraCaptureSession session) 
            Log.d(TAG, "Capture session configure failed: " + session);
            Log.e(TAG, "onConfigureFailed");
        
    ;

    @Override
    public void createCamera(CameraUtility.cameraOpenedListener cameraOpenedListener) 
        this.cameraOpenedListener = cameraOpenedListener;

        startBackgroundThread();
        if(cameraOpenedListener != null)
            cameraOpenedListener.onCameraOpened(true, true, true);
        
        initCamera();
    

    private void releaseCameraComponents()
        try
            cameraOpenCloseLock.acquire();
            if(cameraCaptureSessions != null)
                cameraCaptureSessions.close();
                cameraCaptureSessions = null;
            
            if(cameraDevice != null)
                cameraDevice.close();
                cameraDevice = null;
            
            if(surfaceHolder != null)
                surfaceHolder = null;
            
            if(cameraOpenedListener != null)
                cameraOpenedListener = null;
            
            Log.e(TAG, "cameraComponentsReleased");
         catch (InterruptedException e) 
            throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
         finally 
            cameraOpenCloseLock.release();
        
    
    @Override
    public void releaseCamera() 
        releaseCameraComponents();
        stopBackgroundThread();
    

    @Override
    public void onSurfaceCreated(SurfaceHolder surfaceHolder) 
        Log.e(TAG, "onSurfaceCreated");
        this.surfaceHolder = surfaceHolder;
        openCamera();
    

    @Override
    public void onSurfaceChanged(SurfaceHolder surfaceHolder, int width, int height) 
        Log.e(TAG, "onSurfaceChanged");
        setSurfaceSize(width, height);
    

    @Override
    public void onSurfaceDestroyed(SurfaceHolder surfaceHolder) 
        Log.e(TAG, "onSurfaceDestroyed");
    

    private void startBackgroundThread() 
        Log.e(TAG, "startCameraThread");
        backgroundThread = new HandlerThread("CameraBackground");
        backgroundThread.start();
        backgroundHandler = new Handler(backgroundThread.getLooper());
    

    private void stopBackgroundThread() 
        Log.e(TAG, "StopCameraThread");
        backgroundThread.quitSafely();
        try 
            backgroundThread.join();
            backgroundThread = null;
            backgroundHandler = null;
         catch (InterruptedException e) 
            Log.e(TAG, "Error message: ", e);
        
    

    private void initCamera()
        Log.e(TAG, "initCamera");
        CameraManager cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);

        try
            for (String cameraId : cameraManager.getCameraIdList()) 
                CameraCharacteristics characteristics
                        = cameraManager.getCameraCharacteristics(cameraId);

                // Use back camera
                Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
                if (facing != null && facing == CameraCharacteristics.LENS_FACING_BACK) 
                    backFacingCameraId = cameraId;
                    break;
                
            
            if(backFacingCameraId == null)
                Log.d(TAG, "Could not detect a camera");
            
         catch (CameraAccessException e) 
            Log.e(TAG, "Could not get camera list", e);
        
    

    private void openCamera()
        Log.e(TAG, "openCamera");
        CameraManager cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
        try
            if(backFacingCameraId != null && cameraDevice == null)
                try
                    if (!cameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) 
                        throw new RuntimeException("Time out waiting to lock camera opening.");
                    
                    cameraManager.openCamera(backFacingCameraId, cameraDeviceStateCallback, backgroundHandler);
                 catch (InterruptedException e) 
                    throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
                
            
         catch(SecurityException e)
            Log.e(TAG, "Camera permission is not granted", e);
         catch(CameraAccessException e)
            Log.e(TAG, "Could not open camera", e);
        
    

    private void createCameraPreview()

        Log.e(TAG, "createCameraPreview");
        Surface surface = surfaceHolder.getSurface();

        List<Surface> surfaceList = Collections.singletonList(surface);

        try 
            captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            captureRequestBuilder.addTarget(surface);
            cameraDevice.createCaptureSession(surfaceList, captureSessionStateCallback, null);
         catch (CameraAccessException e)
            Log.e(TAG, "Could not create capture session for camera: " + cameraDevice.getId(), e);
         catch (IllegalStateException e)
            Log.e(TAG, "Camera has been closed", e);
        
    

CameraUtility.interface

interface CameraUtility 

    void createCamera(CameraUtility.cameraOpenedListener cameraOpenedListener);
    void releaseCamera();
    void onSurfaceCreated(SurfaceHolder surfaceHolder);
    void onSurfaceChanged(SurfaceHolder surfaceHolder, int width, int height);
    void onSurfaceDestroyed(SurfaceHolder surfaceHolder);

    interface cameraOpenedListener
        void onCameraOpened(boolean succeeded, boolean addPreview, boolean progressBar);
    

更新

这就是为什么它不会每次都发生。调用 onPause 后立即发生错误,会话开始重复请求以维护预览(onConfigured)。然后 cameraComponentsReleased 在所有清理完成的地方触发,包括当前的 CameraDevice 对象。仍然不知道如何处理这种情况。

03-13 12:12:24.375 17555-17555/pl.tripper.tripper E/MainActivity: onPause
03-13 12:12:24.395 17555-20454/pl.tripper.tripper E/CameraNewApi: onConfigured
03-13 12:12:24.625 17555-17555/pl.tripper.tripper E/CameraNewApi: cameraComponentsReleased
03-13 12:12:24.625 17555-17555/pl.tripper.tripper E/CameraNewApi: StopCameraThread
03-13 12:12:24.625 17555-20454/pl.tripper.tripper E/CameraNewApi: Session was closed or camera device has been closed. 
                                                                  java.lang.IllegalStateException: CameraDevice was already closed
                                                                      at android.hardware.camera2.impl.CameraDeviceImpl.checkIfCameraClosedOrInError(CameraDeviceImpl.java:1997)
                                                                      at android.hardware.camera2.impl.CameraDeviceImpl.submitCaptureRequest(CameraDeviceImpl.java:844)
                                                                      at android.hardware.camera2.impl.CameraDeviceImpl.setRepeatingRequest(CameraDeviceImpl.java:899)
                                                                      at android.hardware.camera2.impl.CameraCaptureSessionImpl.setRepeatingRequest(CameraCaptureSessionImpl.java:236)
                                                                      at pl.tripper.tripper.camera.CameraNewApi$2.onConfigured(CameraNewApi.java:114)
                                                                      at java.lang.reflect.Method.invoke(Native Method)
                                                                      at android.hardware.camera2.dispatch.InvokeDispatcher.dispatch(InvokeDispatcher.java:39)
                                                                      at android.hardware.camera2.dispatch.HandlerDispatcher$1.run(HandlerDispatcher.java:65)
                                                                      at android.os.Handler.handleCallback(Handler.java:739)
                                                                      at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                      at android.os.Looper.loop(Looper.java:158)
                                                                      at android.os.HandlerThread.run(HandlerThread.java:61)
03-13 12:12:24.625 17555-20454/pl.tripper.tripper E/CameraNewApi: Camera onClosed
03-13 12:12:24.625 17555-17555/pl.tripper.tripper E/CameraApiManager: cameraPreviewRemoved

【问题讨论】:

【参考方案1】:
java.lang.IllegalStateException: CameraDevice was already closed

这意味着 CameraDevice 在某些情况下被某人关闭。 (例如:内存不足)要处理此问题,您可以在 StateCallback - cameraDeviceStateCallback 中添加 onClosed() 回调。

android.hardware.camera2.CameraDevice.StateCallback.onClosed(CameraDevice)

更新:

它看起来像一个竞争条件。在日志中,17555-17555 releaseCameraComponents17555-20454 onConfigured 回调在不同的线程上被调用。 IMO,cameraCaptureSessions 应该在releaseCameraComponentsonConfigured 中同步。

private void releaseCameraComponents()
     synchronized(lock) 
          ....
     

....

@Override
public void onConfigured(@NonNull CameraCaptureSession session) 
    synchronized(lock) 
        ....
    

【讨论】:

@You Kim - 我认为你是对的。 camera2Basic 示例有一些可能的竞争条件,但 onConfigured 回调实际上是打开序列中的最后一步,因此将其包含在任何同步计划中是有意义的。 如果您不知道如何像我一样使用它,请查看docs.oracle.com/javase/tutorial/essential/concurrency/…。 我更喜欢处理线程或单个调度程序,以处理摄像头、音频、电话、BLE 等硬件资源,尤其是当资源具有状态时。另外我更喜欢避免在资源回调中调用资源 API。【参考方案2】:
mCameraOpenCloseLock.release()

这个 Semaphore 应该在相机 createCaptureSession 动作之后释放,以防止多个线程之间的资源冲突。源代码在相机打开后过早释放信号量。暂停应用程序将关闭导致错误的相机。

要测试它,在mCameraOpenCloseLock.release()之前调用finish(),你不会看到错误

【讨论】:

你能解释一下如何使用它吗?【参考方案3】:

1> 首先,请创建一个信号量'mCameraOpenCloseLock',以防止应用在关闭相机之前退出。 使用谷歌推荐的例子:- https://github.com/googlesamples/android-Camera2Basic/blob/master/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java

2> 这个信号量是在CameraDevice.StateCallback 的onOpened() 中释放的,这是不正确的,所以请删除它。它应该在 createCameraPreviewSession() 中的 onConfigured() 结束时释放。这意味着在相机预览会话成功完成后释放信号量 mCameraOpenCloseLock。

【讨论】:

以上是关于Camera2 API 和 java.lang.IllegalStateException的主要内容,如果未能解决你的问题,请参考以下文章

Camera2 API 设置自定义白平衡和温度颜色

使用 Android Camera2 API 进行人脸检测和画圆

camera2 api 连拍

问题支持Android相机的API和camera2 API问题,怎么解决

Android 10(api 29)camera2 api回归与广角相机

android Camera2 API使用详解