# Android CameraX en 2026: Captura de Fotos y Videos con Preguntas de Entrevista > Guía completa de CameraX 1.6 para Android: arquitectura lifecycle-aware, captura de fotos, grabación de video, integración con Jetpack Compose y preguntas de entrevista técnica. - Published: 2026-09-11 - Updated: 2026-09-11 - Author: Anthony Fillion-Maillet - Reading time: 5 min --- CameraX simplifica el desarrollo de cámaras en Android al abstraer la complejidad del hardware detrás de una API lifecycle-aware. Con la versión 1.6.2 ahora estable y la migración a CameraPipe completada, CameraX ofrece el mismo stack de cámara de alto rendimiento que impulsa la aplicación de cámara Pixel. > **Cambios Clave en CameraX 1.6** > > CameraX 1.6 migró a CameraPipe, usa Media3 Muxer por defecto para VideoCapture y estabilizó la API SessionConfig. Los builders DSL de Kotlin (`preview { }`, `imageCapture { }`, `videoCapture { }`) reducen el boilerplate en un 40%. ## Arquitectura de CameraX y Modelo de Casos de Uso CameraX proporciona cuatro casos de uso principales que pueden ejecutarse simultáneamente: Preview, ImageCapture, ImageAnalysis y VideoCapture. Cada caso de uso se vincula a un [LifecycleOwner](https://developer.android.com/topic/libraries/architecture/lifecycle), por lo que la cámara se inicia y detiene automáticamente con la actividad o fragmento. El CameraProvider actúa como una factory que instancia estos casos de uso y los vincula a la cámara. Este desacoplamiento significa que el mismo código funciona en dispositivos de diferentes fabricantes sin preocuparse por las particularidades específicas de cada OEM. ```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 vincula casos de uso al lifecycle cameraProvider = ProcessCameraProvider.getInstance(context).await() } fun bindUseCases(previewView: PreviewView) { // Desvincular casos de uso existentes antes de revincular cameraProvider.unbindAll() // Caso de uso Preview muestra el feed de la cámara val preview = Preview.Builder() .build() .apply { setSurfaceProvider(previewView.surfaceProvider) } // ImageCapture para fotos imageCapture = ImageCapture.Builder() .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) .build() // VideoCapture con Recorder val recorder = Recorder.Builder() .setQualitySelector(QualitySelector.from(Quality.FHD)) .build() videoCapture = VideoCapture.withOutput(recorder) // Vincular todos los casos de uso al lifecycle cameraProvider.bindToLifecycle( lifecycleOwner, CameraSelector.DEFAULT_BACK_CAMERA, preview, imageCapture, videoCapture ) } } ``` La llamada `bindToLifecycle` conecta los casos de uso tanto al hardware de la cámara como al lifecycle. Cuando el LifecycleOwner entra en estado STARTED, la cámara se abre. Cuando entra en estado STOPPED, la cámara se cierra automáticamente. ## Implementando Captura de Fotos con ImageCapture ImageCapture proporciona dos modos de captura: `CAPTURE_MODE_MINIMIZE_LATENCY` para una respuesta rápida del obturador, y `CAPTURE_MODE_MAXIMIZE_QUALITY` para tomas que requieren procesamiento intensivo. La elección depende de si la aplicación prioriza velocidad (apps sociales) o calidad (escáneres de documentos). ```kotlin // PhotoCaptureManager.kt class PhotoCaptureManager( private val context: Context, private val imageCapture: ImageCapture ) { private val mainExecutor = ContextCompat.getMainExecutor(context) fun capturePhoto(onResult: (Uri?) -> Unit) { // Generar nombre de archivo único con timestamp val filename = "IMG_${System.currentTimeMillis()}.jpg" val contentValues = ContentValues().apply { put(MediaStore.MediaColumns.DISPLAY_NAME, filename) put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg") // Almacenar en Pictures/CameraX en 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 contiene la URI de MediaStore onResult(results.savedUri) } override fun onError(exception: ImageCaptureException) { Log.e("PhotoCapture", "Captura fallida: ${exception.message}") onResult(null) } } ) } } ``` CameraX 1.5 agregó soporte para captura DNG (RAW) para aplicaciones que necesitan datos sin procesar del sensor. Se debe verificar la capacidad del dispositivo con `ImageCapture.getImageCaptureCapabilities()` antes de habilitar la salida RAW. ## Grabación de Video con VideoCapture y Recorder VideoCapture usa un objeto [Recorder](https://developer.android.com/reference/androidx/camera/video/Recorder) para manejar la codificación y el muxing. La API Recorder sigue un patrón prepare-start-stop que maneja automáticamente la sincronización de audio. ```kotlin // VideoRecordingManager.kt class VideoRecordingManager( private val context: Context, private val videoCapture: VideoCapture ) { private var activeRecording: Recording? = null fun startRecording(onEvent: (VideoRecordEvent) -> Unit): Boolean { // Verificar si ya está grabando 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() // Preparar grabación con audio si se tiene permiso val pendingRecording = videoCapture.output .prepareRecording(context, mediaStoreOutput) if (hasAudioPermission()) { pendingRecording.withAudioEnabled() } // Iniciar grabación y almacenar referencia activeRecording = pendingRecording.start( ContextCompat.getMainExecutor(context) ) { event -> onEvent(event) // Limpiar referencia cuando termina la grabación 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 agregó soporte para video en cámara lenta. Las capacidades pueden consultarse con `Recorder.getHighSpeedVideoCapabilities()` antes de habilitar grabación a 120fps o 240fps. ## CameraX con Jetpack Compose CameraX 1.5 introdujo el artifact `camera-compose` con un composable `CameraXViewfinder`. Para aplicaciones que aún usan PreviewView basado en View, AndroidView proporciona interoperabilidad. ```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) } ) // Botones de captura en overlay Row( modifier = Modifier .align(Alignment.BottomCenter) .padding(32.dp), horizontalArrangement = Arrangement.spacedBy(24.dp) ) { IconButton( onClick = { viewModel.capturePhoto() } ) { Icon(Icons.Default.Camera, "Tomar foto") } IconButton( onClick = { viewModel.toggleRecording() } ) { Icon( if (viewModel.isRecording) Icons.Default.Stop else Icons.Default.Videocam, "Grabar video" ) } } } } ``` Para implementaciones Compose-first, la guía de [preguntas de entrevista de Jetpack Compose](/technologies/android/interview-questions/android-compose) cubre patrones de integración con ViewModel que se aplican directamente a la gestión del estado de la cámara. ## Manejo de Permisos de Cámara Android requiere el permiso CAMERA en tiempo de ejecución. RECORD_AUDIO solo es necesario cuando se graba video con sonido. El flujo de permisos debe explicar por qué se necesita el acceso antes de solicitarlo. ```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) } } } ``` ## Preguntas de Entrevista sobre CameraX CameraX aparece en entrevistas de Android cuando se discute integración de cámara, gestión del lifecycle o abstracción de hardware. Estas preguntas evalúan la comprensión de la arquitectura y los detalles de implementación práctica. ### ¿Por qué usar CameraX en lugar de Camera2? CameraX abstrae las particularidades específicas de dispositivos que Camera2 expone directamente. Una implementación de Camera2 requiere manejar cientos de soluciones alternativas específicas para cada dispositivo. CameraX incorpora estas correcciones en la biblioteca, probadas contra el [CameraX Test Lab](https://android-developers.googleblog.com/2025/11/introducing-camerax-15-powerful-video.html) que cubre más de 150 modelos de dispositivos. La vinculación lifecycle-aware elimina la gestión manual de recursos. Camera2 requiere llamadas explícitas de open/close que causan fugas de memoria si no se manejan correctamente en cada callback del lifecycle. ### ¿Cómo vincula CameraProvider los casos de uso al lifecycle? CameraProvider usa el patrón LifecycleObserver internamente. Al llamar a `bindToLifecycle()`, registra un observador en el LifecycleOwner proporcionado. Este observador recibe eventos ON_START y ON_STOP para abrir y cerrar la cámara. El punto clave: CameraX no inicia la cámara inmediatamente al vincular. Espera a que el lifecycle alcance el estado STARTED, lo cual coincide con el timing de Activity.onStart(). ### ¿Qué sucede cuando se vinculan casos de uso incompatibles? No todas las combinaciones de casos de uso funcionan en todos los dispositivos. Preview + VideoCapture + ImageAnalysis + ImageCapture puede fallar en hardware antiguo. CameraX lanza una IllegalArgumentException en el momento de vincular, no en tiempo de ejecución. La solución es verificar `CameraProvider.hasCamera()` y las capacidades del dispositivo antes de vincular combinaciones complejas. Para aplicaciones críticas, probar explícitamente en dispositivos de gama baja. ### Explicar la diferencia entre CAPTURE_MODE_MINIMIZE_LATENCY y CAPTURE_MODE_MAXIMIZE_QUALITY MINIMIZE_LATENCY reduce el lag del obturador usando pipelines de procesamiento más rápidos, posiblemente omitiendo algunos post-procesamientos. MAXIMIZE_QUALITY aplica procesamiento completo de HDR+, reducción de ruido y captura multi-frame en dispositivos compatibles. El compromiso: el modo latencia captura en 100-200ms, el modo calidad puede tomar 500ms-1s dependiendo de la iluminación. Las apps sociales típicamente eligen latencia. Las apps de escaneo de documentos eligen calidad. ### ¿Cómo maneja CameraX la rotación del dispositivo? CameraX maneja automáticamente la rotación a través del ajuste de target rotation. Por defecto, usa la rotación del Display, pero las apps pueden sobrescribirlo con `setTargetRotation()`. Los datos EXIF de la imagen de salida contienen la etiqueta de orientación correcta. Para PreviewView, el scaleType maneja las diferencias de relación de aspecto. FILL_CENTER recorta para llenar, FIT_CENTER muestra letterboxing. La elección depende de si la app prioriza la vista previa a pantalla completa o evitar el recorte. ## Dependencias y Configuración para CameraX 1.6 La biblioteca CameraX está dividida en múltiples artifacts. Incluir solo lo que la app usa para minimizar el tamaño del APK. ```kotlin // build.gradle.kts (Module: app) dependencies { val cameraxVersion = "1.6.2" // Biblioteca core requerida para todos los casos de uso implementation("androidx.camera:camera-core:$cameraxVersion") // Implementación Camera2 (requerida) implementation("androidx.camera:camera-camera2:$cameraxVersion") // Integración con Lifecycle implementation("androidx.camera:camera-lifecycle:$cameraxVersion") // Caso de uso VideoCapture implementation("androidx.camera:camera-video:$cameraxVersion") // PreviewView y componentes de UI de cámara implementation("androidx.camera:camera-view:$cameraxVersion") // Opcional: Extensions (Modo nocturno, HDR, etc.) implementation("androidx.camera:camera-extensions:$cameraxVersion") // Opcional: Efectos en tiempo real implementation("androidx.camera:camera-effects:$cameraxVersion") } android { // CameraX requiere bytecode Java 11 compileOptions { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 } } ``` El Manifest necesita declaraciones de características y permisos: ```xml ``` Los patrones relacionados para [Kotlin Coroutines](/blog/android/mastering-kotlin-coroutines) aplican al envolver llamadas ListenableFuture de CameraX en funciones suspend. ## Qué Cambia CameraX 1.6 para Apps en Producción CameraX 1.6 trajo tres cambios que afectan implementaciones existentes: 1. **Backend CameraPipe**: El stack de cámara interno ahora usa CameraPipe, la misma arquitectura que la cámara Pixel. Esto mejora el rendimiento en dispositivos Pixel y proporciona una base más limpia para características avanzadas. El código existente no necesita cambios. 2. **Media3 Muxer por defecto**: VideoCapture ahora usa Media3 Muxer en lugar de MediaMuxer. Esto mejora la resiliencia ante crashs: si la app termina durante la grabación, el archivo de video permanece reproducible. La superficie de la API no cambia. 3. **API SessionConfig estable**: Las apps ahora pueden configurar ajustes avanzados de cámara a través de SessionConfig sin anotaciones experimentales. Esto habilita características como el uso simultáneo de cámaras frontal/trasera en dispositivos compatibles. **Ruta de migración**: Actualizar la versión de dependencia. Probar en dispositivos que anteriormente tenían problemas. Las [notas de lanzamiento de CameraX](https://developer.android.com/jetpack/androidx/releases/camera) documentan cualquier cambio de comportamiento entre versiones. - CameraX usa vinculación lifecycle-aware: `bindToLifecycle()` conecta casos de uso tanto al lifecycle de la cámara como de la Activity - Los modos de ImageCapture intercambian latencia por calidad: elegir basándose en el caso de uso, no en la capacidad del dispositivo - VideoCapture requiere configuración del Recorder antes de vincular: preparar las opciones de salida antes de iniciar - El manejo de permisos debe explicar el propósito antes de solicitar: reduce las tasas de rechazo - CameraX 1.6 migró a CameraPipe internamente: no se requieren cambios de API, pero probar en dispositivos objetivo - Las preguntas de entrevista se enfocan en gestión del lifecycle, combinaciones de casos de uso y comparación con Camera2 --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/es/blog/android/camerax-photo-video-capture-interview-questions