publicclassCameraContext{privatestaticfinalStringLOG_TAG=CameraContext.class.getSimpleName();privatefinalCameraManagerWrappercameraManager;privatevolatileHandlerThreadcameraManageThread;privatevolatileCameraThreadHandlercameraThreadHandler;privatevolatileCameraAgentcurrentCamera;publicCameraContext(Contextcontext){cameraManager=newCameraManagerWrapper(context);}publicvoidattachThread(){Log.d(LOG_TAG,"attachThread");if(cameraThreadHandler!=null){cameraThreadHandler.removeCallbacksAndMessages(null);}if(cameraManageThread!=null&&cameraManageThread.isAlive()){cameraManageThread.quitSafely();}cameraManageThread=newHandlerThread("Camera Management Thread");cameraManageThread.start();cameraThreadHandler=newCameraThreadHandler(cameraManageThread.getLooper());}publicvoiddetachThread(){Log.d(LOG_TAG,"detachThread");if(cameraManageThread!=null&&cameraManageThread.isAlive()){cameraManageThread.quitSafely();}}privatevoidcheckThread(){if(cameraManageThread==null||!cameraManageThread.isAlive()){thrownewCameraSetupException("attachThread must be called before any other method invocations.");}}publicvoidopenCamera(Consumer<String>consumer){checkThread();RunnableactionOpen=()->{// ...};Messagemsg=Message.obtain(cameraThreadHandler,actionOpen);msg.what=CameraThreadHandler.MSG_OPEN_CAMERA;msg.sendToTarget();}publicvoidcloseCamera(){checkThread();RunnableactionClose=null;MessagemsgClose=Message.obtain(cameraThreadHandler,actionClose);msgClose.what=CameraThreadHandler.MSG_CLOSE_CAMERA;msgClose.sendToTarget();}}
CameraAgent
还需要对CameraDevice进行封装,把CameraCaptureSession,以及RequestBuilder,封装在内,并且在三大回调Device State Callback,Session State Callback以及Session Capture Callback也都封装在内,因此这些东西的生命周期全都是在CameraDevice内部的。
/* * Strategies: * 1) preview size should not be bigger than screen, which is not necessary. * 2) ratio should match. * 3) pick the largest one. * 4) if not found, use screen size. */privateOptional<CameraSize>calculatePreviewSize(PointscreenSize,floatratio){intwidth=Math.min(screenSize.x,screenSize.y);intheight=Math.min(Math.round(width*ratio),screenSize.y);finalintlimit=screenSize.x*screenSize.y;Log.d(LOG_TAG,"screen size "+screenSize.x+" x "+screenSize.y+", ratio "+ratio+", desired width->"+width+", height->"+height);StreamConfigurationMapstreamMap=characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);Size[]surfaceSizes=streamMap.getOutputSizes(Surface.class);if(surfaceSizes==null){surfaceSizes=streamMap.getOutputSizes(ImageFormat.PRIVATE);}List<CameraSize>supportedSize=Arrays.asList(surfaceSizes).stream().map(CameraSize::new).filter(size->size.height*size.width<=limit).sorted(CameraSize::compare).collect(Collectors.toList());Log.d(LOG_TAG,"supportedSize "+supportedSize);returnsupportedSize.stream().filter(size->size.matchRatio(ratio)).findFirst();
具体做法是,直接移除掉未得到执行的open和其他操作。如果有pending状态的关闭,则要先让其执行,并且把关闭线程的操作放到CameraDevice State Callcback的onDisconnect中,也就是说待CameraDevice完全关闭完成后,才可以终止相机线程:
123456789101112131415161718192021222324252627
publicvoiddetachThread(){Log.d(LOG_TAG,"detachThread");if(cameraThreadHandler!=null){// Drop all pending open actionscameraThreadHandler.removeMessages(CameraThreadHandler.MSG_OPEN_CAMERA);if(cameraThreadHandler.hasMessages(CameraThreadHandler.MSG_CLOSE_CAMERA)){// Ensure close actions are dispatched.try{Thread.sleep(50);}catch(InterruptedExceptione){e.printStackTrace();}}// Drop all other messages.cameraThreadHandler.removeCallbacksAndMessages(null);}// TODO: technically speaking, should do this in handler thread// since all connect/disconnect are done inside handler thread// status might not be synced with caller's thread.if(cameraManageThread!=null&&cameraManageThread.isAlive()){if(currentCamera!=null&¤tCamera.connected()){currentCamera.addDisconnectedAction(()->cameraManageThread.quitSafely());}else{cameraManageThread.quitSafely();}}}