Skip to content

CameraX Torch/Flashlight — Complete Guide

DodaTech Updated 2026-06-24 2 min read

In this tutorial, you'll learn about CameraX Torch/Flashlight. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

The Problem

You call camera.cameraControl.enableTorch(true) but the flashlight doesn't turn on, or isTorchAvailable returns false on a device with a flash.

Wrong Approach ❌

// Enabling torch immediately after binding — camera not ready yet
cameraProvider.bindToLifecycle(this, cameraSelector, preview)
camera!!.cameraControl.enableTorch(true) // Camera not fully initialized

Output: Torch doesn't turn on. No error, no light.

Right Approach ✅

class TorchManager(private val context: Context) {
    private var camera: Camera? = null
    private var cameraProvider: ProcessCameraProvider? = null
    private var isTorchOn = false

    fun startCamera(previewView: PreviewView, onReady: () -> Unit = {}) {
        val cameraProviderFuture = ProcessCameraProvider.getInstance(context)
        cameraProviderFuture.addListener({
            cameraProvider = cameraProviderFuture.get()

            val preview = Preview.Builder().build()
                .also { it.setSurfaceProvider(previewView.surfaceProvider) }

            val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

            try {
                cameraProvider?.unbindAll()
                camera = cameraProvider?.bindToLifecycle(
                    context as LifecycleOwner,
                    cameraSelector,
                    preview
                )
                onReady()
            } catch (e: Exception) {
                Log.e("Torch", "Camera bind failed", e)
            }
        }, ContextCompat.getMainExecutor(context))
    }

    fun toggleTorch(): Boolean {
        val cam = camera ?: return false
        val cameraInfo = cam.cameraInfo

        if (!cameraInfo.torchState.value == true) {
            // Torch not available
            if (cameraInfo.torchState.value == null) return false
        }

        isTorchOn = !isTorchOn
        cam.cameraControl.enableTorch(isTorchOn)
        return isTorchOn
    }

    fun setTorch(on: Boolean) {
        camera?.cameraControl?.enableTorch(on)
        isTorchOn = on
    }

    // Flash mode for image capture (not torch)
    fun setFlashMode(imageCapture: ImageCapture, mode: Int) {
        // ImageCapture.FLASH_MODE_AUTO, _ON, _OFF
        imageCapture.flashMode = mode
    }

    fun isFlashAvailable(): Boolean {
        return camera?.cameraInfo?.hasFlashUnit() ?: false
    }

    // Observe torch state
    fun observeTorchState(callback: (Boolean) -> Unit) {
        camera?.cameraInfo?.torchState?.observe(context as LifecycleOwner) { state ->
            callback(state == TorchState.ON)
        }
    }

    fun release() {
        cameraProvider?.unbindAll()
        camera = null
        isTorchOn = false
    }
}

// Usage
if (torchManager.isFlashAvailable()) {
    torchManager.toggleTorch()
}

Output: Torch works correctly with proper camera initialization.

Prevention

  • Wait for camera binding to complete before toggling torch.
  • Check hasFlashUnit() before attempting torch.
  • Observe torchState for reactive UI updates.
  • For photo capture, use imageCapture.flashMode instead of torch.
  • Torch only works when the camera is bound to a lifecycle.

Common Mistakes with camera x torch

  1. Overlapping type class instances that cause GHC to reject the program with ambiguous dispatch errors
  2. Non-exhaustive pattern matches that compile with warnings then crash at runtime
  3. Misunderstanding that String is [Char] with poor performance for large text operations

These mistakes appear frequently in real-world Android code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

### What is the difference between torch and flash?

Torch is continuous light (for video/preview). Flash is a brief burst during image capture. Use cameraControl.enableTorch() for torch, imageCapture.flashMode for flash.

### Why is torch not available on some devices?

The device may not have a flash LED, or the camera is already in use by another app. Check cameraInfo.hasFlashUnit() before showing the torch toggle.

### Does torch work with front camera?

Some front cameras have a screen flash (screen turns white) instead of an LED flash. Torch typically works only with the back camera's flash LED.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro