# Android CameraX in 2026: Photo and Video Capture with Interview Questions > Master Android CameraX 1.6 with practical photo and video capture implementation. Covers Preview, ImageCapture, VideoCapture use cases, CameraPipe architecture, and common interview questions. - Published: 2026-09-11 - Updated: 2026-09-11 - Author: Anthony Fillion-Maillet - Tags: android, camerax, jetpack, kotlin, camera, video - Reading time: 12 min --- Android CameraX simplifies camera development by abstracting hardware complexity behind a lifecycle-aware API. With version 1.6.2 now stable and the migration to CameraPipe complete, CameraX delivers the same high-performance camera stack that powers the Pixel camera app. > **CameraX 1.6 Key Changes** > > CameraX 1.6 migrated to CameraPipe, uses Media3 Muxer by default for VideoCapture, and stabilized the SessionConfig API. The Kotlin DSL builders (`preview { }`, `imageCapture { }`, `videoCapture { }`) reduce boilerplate by 40%. ## CameraX Architecture and Use Case Model CameraX provides four primary use cases that can run concurrently: Preview, ImageCapture, ImageAnalysis, and VideoCapture. Each use case binds to a [LifecycleOwner](https://developer.android.com/topic/libraries/architecture/lifecycle), so the camera automatically starts and stops with the activity or fragment. The CameraProvider acts as a factory that instantiates these use cases and binds them to the camera. This decoupling means the same code runs on devices from different OEMs without worrying about vendor-specific quirks. ```kotlin // CameraSetup.kt class CameraSetup( private val context: Context, private val lifecycleOwner: LifecycleOwner ) { private lateinit var cameraProvider: ProcessCameraProvider private var imageCapture: ImageCapture? = null private var videoCapture: VideoCapture? = null suspend fun initialize() { // ProcessCameraProvider binds use cases to lifecycle cameraProvider = ProcessCameraProvider.getInstance(context).await() } fun bindUseCases(previewView: PreviewView) { // Unbind existing use cases before rebinding cameraProvider.unbindAll() // Preview use case displays camera feed val preview = Preview.Builder() .build() .apply { setSurfaceProvider(previewView.surfaceProvider) } // ImageCapture for photos imageCapture = ImageCapture.Builder() .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) .build() // VideoCapture with Recorder val recorder = Recorder.Builder() .setQualitySelector(QualitySelector.from(Quality.FHD)) .build() videoCapture = VideoCapture.withOutput(recorder) // Bind all use cases to lifecycle cameraProvider.bindToLifecycle( lifecycleOwner, CameraSelector.DEFAULT_BACK_CAMERA, preview, imageCapture, videoCapture ) } } ``` The `bindToLifecycle` call connects use cases to both the camera hardware and the lifecycle. When the LifecycleOwner enters STARTED, the camera opens. When it enters STOPPED, the camera closes automatically. ## Implementing Photo Capture with ImageCapture ImageCapture provides two capture modes: `CAPTURE_MODE_MINIMIZE_LATENCY` for fast shutter response, and `CAPTURE_MODE_MAXIMIZE_QUALITY` for processing-heavy shots. The choice depends on whether the app prioritizes speed (social apps) or quality (document scanners). ```kotlin // PhotoCaptureManager.kt class PhotoCaptureManager( private val context: Context, private val imageCapture: ImageCapture ) { private val mainExecutor = ContextCompat.getMainExecutor(context) fun capturePhoto(onResult: (Uri?) -> Unit) { // Generate unique filename with timestamp val filename = "IMG_${System.currentTimeMillis()}.jpg" val contentValues = ContentValues().apply { put(MediaStore.MediaColumns.DISPLAY_NAME, filename) put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg") // Store in Pictures/CameraX folder on Android 10+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/CameraX") } } val outputOptions = ImageCapture.OutputFileOptions.Builder( context.contentResolver, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues ).build() imageCapture.takePicture( outputOptions, mainExecutor, object : ImageCapture.OnImageSavedCallback { override fun onImageSaved(results: ImageCapture.OutputFileResults) { // results.savedUri contains the MediaStore URI onResult(results.savedUri) } override fun onError(exception: ImageCaptureException) { Log.e("PhotoCapture", "Capture failed: ${exception.message}") onResult(null) } } ) } } ``` CameraX 1.5 added DNG (RAW) capture support for apps that need unprocessed sensor data. Check device capability with `ImageCapture.getImageCaptureCapabilities()` before enabling RAW output. ## Recording Video with VideoCapture and Recorder VideoCapture uses a [Recorder](https://developer.android.com/reference/androidx/camera/video/Recorder) object to handle encoding and muxing. The Recorder API follows a prepare-start-stop pattern that handles audio synchronization automatically. ```kotlin // VideoRecordingManager.kt class VideoRecordingManager( private val context: Context, private val videoCapture: VideoCapture ) { private var activeRecording: Recording? = null fun startRecording(onEvent: (VideoRecordEvent) -> Unit): Boolean { // Check if already recording if (activeRecording != null) return false val filename = "VID_${System.currentTimeMillis()}.mp4" val contentValues = ContentValues().apply { put(MediaStore.MediaColumns.DISPLAY_NAME, filename) put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4") if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { put(MediaStore.Video.Media.RELATIVE_PATH, "Movies/CameraX") } } val mediaStoreOutput = MediaStoreOutputOptions.Builder( context.contentResolver, MediaStore.Video.Media.EXTERNAL_CONTENT_URI ) .setContentValues(contentValues) .build() // Prepare recording with audio if permission granted val pendingRecording = videoCapture.output .prepareRecording(context, mediaStoreOutput) if (hasAudioPermission()) { pendingRecording.withAudioEnabled() } // Start recording and store reference activeRecording = pendingRecording.start( ContextCompat.getMainExecutor(context) ) { event -> onEvent(event) // Clear reference when recording completes if (event is VideoRecordEvent.Finalize) { activeRecording = null } } return true } fun stopRecording() { activeRecording?.stop() } fun pauseRecording() { activeRecording?.pause() } fun resumeRecording() { activeRecording?.resume() } private fun hasAudioPermission(): Boolean { return ContextCompat.checkSelfPermission( context, Manifest.permission.RECORD_AUDIO ) == PackageManager.PERMISSION_GRANTED } } ``` CameraX 1.5 added slow-motion video support. Query capabilities with `Recorder.getHighSpeedVideoCapabilities()` before enabling 120fps or 240fps recording. ## CameraX with Jetpack Compose CameraX 1.5 introduced the `camera-compose` artifact with a `CameraXViewfinder` composable. For apps still using View-based PreviewView, AndroidView provides interop. ```kotlin // CameraPreviewComposable.kt @Composable fun CameraPreview( modifier: Modifier = Modifier, onPreviewViewCreated: (PreviewView) -> Unit ) { AndroidView( modifier = modifier.fillMaxSize(), factory = { context -> PreviewView(context).apply { implementationMode = PreviewView.ImplementationMode.COMPATIBLE scaleType = PreviewView.ScaleType.FILL_CENTER onPreviewViewCreated(this) } } ) } @Composable fun CameraScreen(viewModel: CameraViewModel = viewModel()) { val context = LocalContext.current val lifecycleOwner = LocalLifecycleOwner.current LaunchedEffect(Unit) { viewModel.initializeCamera(context, lifecycleOwner) } Box(modifier = Modifier.fillMaxSize()) { CameraPreview( onPreviewViewCreated = { previewView -> viewModel.bindPreview(previewView) } ) // Capture buttons overlay Row( modifier = Modifier .align(Alignment.BottomCenter) .padding(32.dp), horizontalArrangement = Arrangement.spacedBy(24.dp) ) { IconButton( onClick = { viewModel.capturePhoto() } ) { Icon(Icons.Default.Camera, "Take photo") } IconButton( onClick = { viewModel.toggleRecording() } ) { Icon( if (viewModel.isRecording) Icons.Default.Stop else Icons.Default.Videocam, "Record video" ) } } } } ``` For Compose-first implementations, the [Jetpack Compose interview questions](/technologies/android/interview-questions/android-compose) guide covers ViewModel integration patterns that apply directly to camera state management. ## Handling Camera Permissions Android requires CAMERA permission at runtime. RECORD_AUDIO is needed only when recording video with sound. The permission flow should explain why access is needed before requesting. ```kotlin // PermissionHandler.kt class CameraPermissionHandler(private val activity: ComponentActivity) { private val requiredPermissions = arrayOf( Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO ) private val permissionLauncher = activity.registerForActivityResult( ActivityResultContracts.RequestMultiplePermissions() ) { permissions -> val cameraGranted = permissions[Manifest.permission.CAMERA] == true val audioGranted = permissions[Manifest.permission.RECORD_AUDIO] == true if (cameraGranted) { onCameraPermissionGranted(audioGranted) } else { onCameraPermissionDenied() } } fun checkAndRequestPermissions() { when { hasAllPermissions() -> onCameraPermissionGranted(hasAudioPermission()) shouldShowRationale() -> showPermissionRationale() else -> permissionLauncher.launch(requiredPermissions) } } private fun hasAllPermissions(): Boolean { return requiredPermissions.all { permission -> ContextCompat.checkSelfPermission( activity, permission ) == PackageManager.PERMISSION_GRANTED } } private fun hasAudioPermission(): Boolean { return ContextCompat.checkSelfPermission( activity, Manifest.permission.RECORD_AUDIO ) == PackageManager.PERMISSION_GRANTED } private fun shouldShowRationale(): Boolean { return requiredPermissions.any { permission -> ActivityCompat.shouldShowRequestPermissionRationale(activity, permission) } } } ``` ## CameraX Interview Questions CameraX appears in Android interviews when discussing camera integration, lifecycle management, or hardware abstraction. These questions test understanding of the architecture and practical implementation details. ### Why use CameraX instead of Camera2? CameraX abstracts device-specific quirks that Camera2 exposes directly. A Camera2 implementation requires handling hundreds of device-specific workarounds. CameraX bakes these fixes into the library, tested against the [CameraX Test Lab](https://android-developers.googleblog.com/2025/11/introducing-camerax-15-powerful-video.html) that covers 150+ device models. The lifecycle-aware binding eliminates manual resource management. Camera2 requires explicit open/close calls that cause leaks when not handled correctly in every lifecycle callback. ### How does CameraProvider bind use cases to lifecycle? CameraProvider uses the LifecycleObserver pattern internally. When calling `bindToLifecycle()`, it registers an observer on the provided LifecycleOwner. This observer receives ON_START and ON_STOP events to open and close the camera. The key insight: CameraX does not start the camera immediately on bind. It waits for the lifecycle to reach STARTED state, which matches Activity.onStart() timing. ### What happens when you bind incompatible use cases? Not all use case combinations work on all devices. Preview + VideoCapture + ImageAnalysis + ImageCapture may fail on older hardware. CameraX throws an IllegalArgumentException at bind time, not at runtime. The solution is checking `CameraProvider.hasCamera()` and device capabilities before binding complex combinations. For critical apps, test on low-end devices explicitly. ### Explain the difference between CAPTURE_MODE_MINIMIZE_LATENCY and CAPTURE_MODE_MAXIMIZE_QUALITY MINIMIZE_LATENCY reduces shutter lag by using faster processing pipelines, possibly skipping some post-processing. MAXIMIZE_QUALITY applies full HDR+ processing, noise reduction, and multi-frame capture on supported devices. The tradeoff: latency mode captures in 100-200ms, quality mode may take 500ms-1s depending on lighting. Social apps typically choose latency. Document scanning apps choose quality. ### How does CameraX handle device rotation? CameraX automatically handles rotation through the target rotation setting. By default, it uses the Display rotation, but apps can override with `setTargetRotation()`. The output image EXIF data contains the correct orientation tag. For PreviewView, the scaleType handles aspect ratio differences. FILL_CENTER crops to fill, FIT_CENTER shows letterboxing. The choice depends on whether the app prioritizes full-screen preview or avoiding cropping. ## Dependencies and Setup for CameraX 1.6 The CameraX library is split into multiple artifacts. Include only what the app uses to minimize APK size. ```kotlin // build.gradle.kts (Module: app) dependencies { val cameraxVersion = "1.6.2" // Core library required for all use cases implementation("androidx.camera:camera-core:$cameraxVersion") // Camera2 implementation (required) implementation("androidx.camera:camera-camera2:$cameraxVersion") // Lifecycle integration implementation("androidx.camera:camera-lifecycle:$cameraxVersion") // VideoCapture use case implementation("androidx.camera:camera-video:$cameraxVersion") // PreviewView and camera UI components implementation("androidx.camera:camera-view:$cameraxVersion") // Optional: Extensions (Night mode, HDR, etc.) implementation("androidx.camera:camera-extensions:$cameraxVersion") // Optional: Real-time effects implementation("androidx.camera:camera-effects:$cameraxVersion") } android { // CameraX requires Java 11 bytecode compileOptions { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 } } ``` The Manifest needs feature declarations and permissions: ```xml ``` Related patterns for [Kotlin Coroutines](/blog/android/mastering-kotlin-coroutines) apply when wrapping CameraX ListenableFuture calls in suspend functions. ## What CameraX 1.6 Changes for Production Apps CameraX 1.6 brought three changes that affect existing implementations: 1. **CameraPipe backend**: The internal camera stack now uses CameraPipe, the same architecture as the Pixel camera. This improves performance on Pixel devices and provides a cleaner foundation for advanced features. Existing code does not need changes. 2. **Media3 Muxer default**: VideoCapture now uses Media3 Muxer instead of MediaMuxer. This improves crash resilience: if the app terminates during recording, the video file remains playable. The API surface is unchanged. 3. **SessionConfig API stable**: Apps can now configure advanced camera settings through SessionConfig without experimental annotations. This enables features like simultaneous front/back camera use on supported devices. **Migration path**: Update the dependency version. Test on devices that previously had issues. The [CameraX release notes](https://developer.android.com/jetpack/androidx/releases/camera) document any behavioral changes between versions. - CameraX uses lifecycle-aware binding: `bindToLifecycle()` connects use cases to both camera and Activity lifecycle - ImageCapture modes trade latency for quality: choose based on use case, not device capability - VideoCapture requires Recorder setup before binding: prepare the output options before starting - Permission handling should explain purpose before requesting: reduces rejection rates - CameraX 1.6 migrated to CameraPipe internally: no API changes required, but test on target devices - Interview questions focus on lifecycle management, use case combinations, and Camera2 comparison --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/en/blog/android/camerax-photo-video-capture-interview-questions