Search code examples
androidandroid-camerax

Is bindToLifecycle() is necessary to switch ON/OFF/AUTO flash every time after creating preview in CameraX library


As I understand from many implementations such as :

https://github.com/android/camera-samples/tree/master/CameraXBasic

https://proandroiddev.com/android-camerax-preview-analyze-capture-1b3f403a9395

After every use case in CameraX implementation cameraProvide.bindToLifecycle() method needs to be called.

For example, if I need to switch ON the FLASH_MODE of the camera from the default OFF mode, then again bindToLifecycle() method needs to be called.

The disadvantage with this approach is that for a second or two the preview is removed and re-attached which doesn't feel like a smooth transition for an app.

Is there any better practice available or it is the limitation?

I Have attached a sample code below:

   private void bindCameraUseCase() {
    int screenAspectRatio = getAspectRatio(previewView.getWidth(), previewView.getHeight());
    int rotation = previewView.getDisplay().getRotation();
    preview = new Preview.Builder()
            .setTargetAspectRatio(screenAspectRatio)
            .setTargetRotation(rotation)
            .build();
    cameraSelector = new CameraSelector.Builder()
            .requireLensFacing(lensFacing)
            .build();
    imageCapture = new ImageCapture.Builder()
            .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
            .setTargetAspectRatio(screenAspectRatio)
            .setTargetRotation(rotation)
            .setFlashMode(flashMode)
            .build();
    // Must unbind the use-cases before rebinding them
    cameraProvider.unbindAll();
    preview.setSurfaceProvider(previewView.createSurfaceProvider());
    camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture);
}

And to toggle flashlight:

    private void toggleFlash(){
    Log.d(TAG, "toggleFlash: "+flashMode);
    switch (flashMode){
        case ImageCapture.FLASH_MODE_OFF:
            flashMode = ImageCapture.FLASH_MODE_ON;
            flashButton.setBackgroundResource(R.drawable.ic_flash_on_24dp);
            break;
        case ImageCapture.FLASH_MODE_ON:
            flashMode = ImageCapture.FLASH_MODE_AUTO;
            break;
        case ImageCapture.FLASH_MODE_AUTO:
            flashMode = ImageCapture.FLASH_MODE_OFF;
            break;
    }
    bindCameraUseCase();
}

I'm using CameraX version - 1.0.0-beta04


Solution

  • To enable or disable the flash during an image capture after you've created an ImageCapture instance and bound it to a lifecycle, you can use ImageCapture.setFlashMode(boolean).

    Regarding your question about the difference between setting the flash mode before vs after binding the ImageCapture use case, AFAIK there isn't much of a difference really. When you take a picture by calling ImageCapture.takePicture(), a capture request is built using different configuration parameters, one of them is the flash mode. So as long as the flash mode is set before this call (ImageCapture.takePicture()), the output of the capture request should be the same.

    CameraX currently uses Camera2 under the hood, to better understand how the flash mode is set when taking a picture, you can take a look at CaptureRequest.FLASH_MODE.