# Android CameraX en 2026 : Capture Photo et Vidéo avec Questions d'Entretien > Guide complet CameraX 1.6 pour Android : architecture lifecycle-aware, capture photo, enregistrement vidéo, intégration Jetpack Compose et questions d'entretien technique. - Published: 2026-09-11 - Updated: 2026-09-11 - Author: Anthony Fillion-Maillet - Reading time: 5 min --- CameraX simplifie le développement caméra Android en abstrayant la complexité matérielle derrière une API lifecycle-aware. Avec la version 1.6.2 désormais stable et la migration vers CameraPipe achevée, CameraX offre la même pile caméra haute performance qui équipe l'application appareil photo Pixel. > **Changements Clés CameraX 1.6** > > CameraX 1.6 a migré vers CameraPipe, utilise Media3 Muxer par défaut pour VideoCapture et a stabilisé l'API SessionConfig. Les builders DSL Kotlin (`preview { }`, `imageCapture { }`, `videoCapture { }`) réduisent le boilerplate de 40%. ## Architecture CameraX et Modèle de Cas d'Usage CameraX fournit quatre cas d'usage principaux qui peuvent s'exécuter simultanément : Preview, ImageCapture, ImageAnalysis et VideoCapture. Chaque cas d'usage se lie à un [LifecycleOwner](https://developer.android.com/topic/libraries/architecture/lifecycle), de sorte que la caméra démarre et s'arrête automatiquement avec l'activité ou le fragment. Le CameraProvider agit comme une factory qui instancie ces cas d'usage et les lie à la caméra. Ce découplage signifie que le même code fonctionne sur des appareils de différents fabricants sans se soucier des particularités spécifiques à chaque constructeur. ```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 lie les cas d'usage au lifecycle cameraProvider = ProcessCameraProvider.getInstance(context).await() } fun bindUseCases(previewView: PreviewView) { // Délier les cas d'usage existants avant de relier cameraProvider.unbindAll() // Cas d'usage Preview affiche le flux caméra val preview = Preview.Builder() .build() .apply { setSurfaceProvider(previewView.surfaceProvider) } // ImageCapture pour les photos imageCapture = ImageCapture.Builder() .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) .build() // VideoCapture avec Recorder val recorder = Recorder.Builder() .setQualitySelector(QualitySelector.from(Quality.FHD)) .build() videoCapture = VideoCapture.withOutput(recorder) // Lier tous les cas d'usage au lifecycle cameraProvider.bindToLifecycle( lifecycleOwner, CameraSelector.DEFAULT_BACK_CAMERA, preview, imageCapture, videoCapture ) } } ``` L'appel `bindToLifecycle` connecte les cas d'usage à la fois au matériel caméra et au lifecycle. Lorsque le LifecycleOwner entre dans l'état STARTED, la caméra s'ouvre. Lorsqu'il entre dans l'état STOPPED, la caméra se ferme automatiquement. ## Implémentation de la Capture Photo avec ImageCapture ImageCapture propose deux modes de capture : `CAPTURE_MODE_MINIMIZE_LATENCY` pour une réponse rapide du déclencheur, et `CAPTURE_MODE_MAXIMIZE_QUALITY` pour les prises de vue nécessitant un traitement intensif. Le choix dépend de la priorité de l'application : vitesse (applications sociales) ou qualité (scanners de documents). ```kotlin // PhotoCaptureManager.kt class PhotoCaptureManager( private val context: Context, private val imageCapture: ImageCapture ) { private val mainExecutor = ContextCompat.getMainExecutor(context) fun capturePhoto(onResult: (Uri?) -> Unit) { // Générer un nom de fichier unique avec horodatage val filename = "IMG_${System.currentTimeMillis()}.jpg" val contentValues = ContentValues().apply { put(MediaStore.MediaColumns.DISPLAY_NAME, filename) put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg") // Stocker dans Pictures/CameraX sur 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 contient l'URI MediaStore onResult(results.savedUri) } override fun onError(exception: ImageCaptureException) { Log.e("PhotoCapture", "Échec de capture : ${exception.message}") onResult(null) } } ) } } ``` CameraX 1.5 a ajouté le support de capture DNG (RAW) pour les applications nécessitant des données brutes du capteur. Il convient de vérifier les capacités de l'appareil avec `ImageCapture.getImageCaptureCapabilities()` avant d'activer la sortie RAW. ## Enregistrement Vidéo avec VideoCapture et Recorder VideoCapture utilise un objet [Recorder](https://developer.android.com/reference/androidx/camera/video/Recorder) pour gérer l'encodage et le muxing. L'API Recorder suit un pattern prepare-start-stop qui gère automatiquement la synchronisation 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 { // Vérifier si un enregistrement est déjà en cours 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() // Préparer l'enregistrement avec audio si permission accordée val pendingRecording = videoCapture.output .prepareRecording(context, mediaStoreOutput) if (hasAudioPermission()) { pendingRecording.withAudioEnabled() } // Démarrer l'enregistrement et stocker la référence activeRecording = pendingRecording.start( ContextCompat.getMainExecutor(context) ) { event -> onEvent(event) // Effacer la référence quand l'enregistrement termine 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 a ajouté le support vidéo au ralenti. Les capacités peuvent être interrogées avec `Recorder.getHighSpeedVideoCapabilities()` avant d'activer l'enregistrement à 120fps ou 240fps. ## CameraX avec Jetpack Compose CameraX 1.5 a introduit l'artifact `camera-compose` avec un composable `CameraXViewfinder`. Pour les applications utilisant encore PreviewView basé sur View, AndroidView fournit l'interopérabilité. ```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) } ) // Boutons de capture en overlay Row( modifier = Modifier .align(Alignment.BottomCenter) .padding(32.dp), horizontalArrangement = Arrangement.spacedBy(24.dp) ) { IconButton( onClick = { viewModel.capturePhoto() } ) { Icon(Icons.Default.Camera, "Prendre une photo") } IconButton( onClick = { viewModel.toggleRecording() } ) { Icon( if (viewModel.isRecording) Icons.Default.Stop else Icons.Default.Videocam, "Enregistrer une vidéo" ) } } } } ``` Pour les implémentations Compose-first, le guide sur les [questions d'entretien Jetpack Compose](/technologies/android/interview-questions/android-compose) couvre les patterns d'intégration ViewModel qui s'appliquent directement à la gestion d'état de la caméra. ## Gestion des Permissions Caméra Android requiert la permission CAMERA au runtime. RECORD_AUDIO n'est nécessaire que lors de l'enregistrement vidéo avec son. Le flux de permission doit expliquer pourquoi l'accès est nécessaire avant de le demander. ```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) } } } ``` ## Questions d'Entretien CameraX CameraX apparaît dans les entretiens Android lors de discussions sur l'intégration caméra, la gestion du lifecycle ou l'abstraction matérielle. Ces questions testent la compréhension de l'architecture et les détails d'implémentation pratiques. ### Pourquoi utiliser CameraX plutôt que Camera2 ? CameraX abstrait les particularités spécifiques aux appareils que Camera2 expose directement. Une implémentation Camera2 nécessite de gérer des centaines de contournements spécifiques aux appareils. CameraX intègre ces corrections dans la bibliothèque, testées contre le [CameraX Test Lab](https://android-developers.googleblog.com/2025/11/introducing-camerax-15-powerful-video.html) qui couvre plus de 150 modèles d'appareils. La liaison lifecycle-aware élimine la gestion manuelle des ressources. Camera2 nécessite des appels explicites open/close qui provoquent des fuites mémoire s'ils ne sont pas gérés correctement dans chaque callback de lifecycle. ### Comment CameraProvider lie-t-il les cas d'usage au lifecycle ? CameraProvider utilise le pattern LifecycleObserver en interne. Lors de l'appel à `bindToLifecycle()`, il enregistre un observateur sur le LifecycleOwner fourni. Cet observateur reçoit les événements ON_START et ON_STOP pour ouvrir et fermer la caméra. Le point clé : CameraX ne démarre pas la caméra immédiatement au binding. Il attend que le lifecycle atteigne l'état STARTED, ce qui correspond au timing de Activity.onStart(). ### Que se passe-t-il lors de la liaison de cas d'usage incompatibles ? Toutes les combinaisons de cas d'usage ne fonctionnent pas sur tous les appareils. Preview + VideoCapture + ImageAnalysis + ImageCapture peut échouer sur du matériel ancien. CameraX lance une IllegalArgumentException au moment du binding, pas au runtime. La solution consiste à vérifier `CameraProvider.hasCamera()` et les capacités de l'appareil avant de lier des combinaisons complexes. Pour les applications critiques, tester explicitement sur des appareils d'entrée de gamme. ### Expliquer la différence entre CAPTURE_MODE_MINIMIZE_LATENCY et CAPTURE_MODE_MAXIMIZE_QUALITY MINIMIZE_LATENCY réduit le délai du déclencheur en utilisant des pipelines de traitement plus rapides, en sautant possiblement certains post-traitements. MAXIMIZE_QUALITY applique le traitement complet HDR+, la réduction de bruit et la capture multi-frames sur les appareils supportés. Le compromis : le mode latence capture en 100-200ms, le mode qualité peut prendre 500ms-1s selon l'éclairage. Les applications sociales choisissent typiquement la latence. Les applications de scan de documents choisissent la qualité. ### Comment CameraX gère-t-il la rotation de l'appareil ? CameraX gère automatiquement la rotation via le paramètre target rotation. Par défaut, il utilise la rotation du Display, mais les applications peuvent surcharger avec `setTargetRotation()`. Les données EXIF de l'image de sortie contiennent le tag d'orientation correct. Pour PreviewView, le scaleType gère les différences de ratio d'aspect. FILL_CENTER recadre pour remplir, FIT_CENTER affiche des bandes noires. Le choix dépend de si l'application privilégie l'aperçu plein écran ou évite le recadrage. ## Dépendances et Configuration pour CameraX 1.6 La bibliothèque CameraX est divisée en plusieurs artifacts. Inclure uniquement ce que l'application utilise pour minimiser la taille de l'APK. ```kotlin // build.gradle.kts (Module: app) dependencies { val cameraxVersion = "1.6.2" // Bibliothèque core requise pour tous les cas d'usage implementation("androidx.camera:camera-core:$cameraxVersion") // Implémentation Camera2 (requise) implementation("androidx.camera:camera-camera2:$cameraxVersion") // Intégration Lifecycle implementation("androidx.camera:camera-lifecycle:$cameraxVersion") // Cas d'usage VideoCapture implementation("androidx.camera:camera-video:$cameraxVersion") // PreviewView et composants UI caméra implementation("androidx.camera:camera-view:$cameraxVersion") // Optionnel: Extensions (Mode nuit, HDR, etc.) implementation("androidx.camera:camera-extensions:$cameraxVersion") // Optionnel: Effets temps réel implementation("androidx.camera:camera-effects:$cameraxVersion") } android { // CameraX nécessite le bytecode Java 11 compileOptions { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 } } ``` Le Manifest nécessite les déclarations de fonctionnalités et les permissions : ```xml ``` Les patterns associés pour [Kotlin Coroutines](/blog/android/mastering-kotlin-coroutines) s'appliquent lors de l'encapsulation des appels ListenableFuture de CameraX dans des fonctions suspend. ## Ce que CameraX 1.6 Change pour les Applications en Production CameraX 1.6 a apporté trois changements qui affectent les implémentations existantes : 1. **Backend CameraPipe** : La pile caméra interne utilise maintenant CameraPipe, la même architecture que la caméra Pixel. Cela améliore les performances sur les appareils Pixel et fournit une fondation plus propre pour les fonctionnalités avancées. Le code existant n'a pas besoin de modifications. 2. **Media3 Muxer par défaut** : VideoCapture utilise maintenant Media3 Muxer au lieu de MediaMuxer. Cela améliore la résilience aux crashs : si l'application se termine pendant l'enregistrement, le fichier vidéo reste lisible. La surface d'API reste inchangée. 3. **API SessionConfig stable** : Les applications peuvent maintenant configurer des paramètres caméra avancés via SessionConfig sans annotations expérimentales. Cela permet des fonctionnalités comme l'utilisation simultanée des caméras avant/arrière sur les appareils supportés. **Chemin de migration** : Mettre à jour la version de dépendance. Tester sur les appareils qui présentaient auparavant des problèmes. Les [notes de version CameraX](https://developer.android.com/jetpack/androidx/releases/camera) documentent tout changement de comportement entre versions. - CameraX utilise la liaison lifecycle-aware : `bindToLifecycle()` connecte les cas d'usage à la fois au lifecycle de la caméra et de l'Activity - Les modes ImageCapture échangent latence contre qualité : choisir en fonction du cas d'usage, pas des capacités de l'appareil - VideoCapture nécessite la configuration du Recorder avant binding : préparer les options de sortie avant de démarrer - La gestion des permissions doit expliquer le but avant de demander : réduit les taux de refus - CameraX 1.6 a migré vers CameraPipe en interne : aucun changement d'API requis, mais tester sur les appareils cibles - Les questions d'entretien se concentrent sur la gestion du lifecycle, les combinaisons de cas d'usage et la comparaison avec Camera2 --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/fr/blog/android/camerax-photo-video-capture-interview-questions