# Android CameraX in 2026: Foto- en Video-opname met Sollicitatievragen > CameraX tutorial voor Android-ontwikkelaars: lifecycle management, foto- en video-opname met Jetpack Compose en technische sollicitatievragen. - Published: 2026-09-11 - Updated: 2026-09-11 - Author: Anthony Fillion-Maillet - Reading time: 5 min --- Android CameraX vereenvoudigt camera-ontwikkeling door hardwarecomplexiteit te abstraheren achter een lifecycle-aware API. Met versie 1.6.2 nu stabiel en de migratie naar CameraPipe voltooid, levert CameraX dezelfde high-performance camera stack die de Pixel camera-app aandrijft. > **CameraX 1.6 Belangrijke Wijzigingen** > > CameraX 1.6 migreerde naar CameraPipe, gebruikt standaard Media3 Muxer voor VideoCapture en stabiliseerde de SessionConfig API. De Kotlin DSL builders (`preview { }`, `imageCapture { }`, `videoCapture { }`) verminderen boilerplate met 40%. ## CameraX Architectuur en Use Case Model CameraX biedt vier primaire use cases die gelijktijdig kunnen draaien: Preview, ImageCapture, ImageAnalysis en VideoCapture. Elke use case bindt aan een [LifecycleOwner](https://developer.android.com/topic/libraries/architecture/lifecycle), zodat de camera automatisch start en stopt met de activity of fragment. De CameraProvider fungeert als factory die deze use cases instantieert en aan de camera bindt. Deze ontkoppeling betekent dat dezelfde code draait op apparaten van verschillende OEM's zonder zich zorgen te maken over leverancierspecifieke eigenaardigheden. ```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 bindt use cases aan lifecycle cameraProvider = ProcessCameraProvider.getInstance(context).await() } fun bindUseCases(previewView: PreviewView) { // Bestaande use cases losmaken voor opnieuw binden cameraProvider.unbindAll() // Preview use case toont camera feed val preview = Preview.Builder() .build() .apply { setSurfaceProvider(previewView.surfaceProvider) } // ImageCapture voor foto's imageCapture = ImageCapture.Builder() .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) .build() // VideoCapture met Recorder val recorder = Recorder.Builder() .setQualitySelector(QualitySelector.from(Quality.FHD)) .build() videoCapture = VideoCapture.withOutput(recorder) // Alle use cases aan lifecycle binden cameraProvider.bindToLifecycle( lifecycleOwner, CameraSelector.DEFAULT_BACK_CAMERA, preview, imageCapture, videoCapture ) } } ``` De `bindToLifecycle` aanroep verbindt use cases met zowel de camera hardware als de lifecycle. Wanneer de LifecycleOwner STARTED bereikt, opent de camera. Wanneer deze STOPPED bereikt, sluit deze automatisch. ## Implementatie van Foto-opname met ImageCapture ImageCapture biedt twee opnamemodi: `CAPTURE_MODE_MINIMIZE_LATENCY` voor snelle sluiterrespons en `CAPTURE_MODE_MAXIMIZE_QUALITY` voor verwerkingsintensieve opnames. De keuze hangt af van of de app snelheid (sociale apps) of kwaliteit (documentenscanners) prioriteert. ```kotlin // PhotoCaptureManager.kt class PhotoCaptureManager( private val context: Context, private val imageCapture: ImageCapture ) { private val mainExecutor = ContextCompat.getMainExecutor(context) fun capturePhoto(onResult: (Uri?) -> Unit) { // Unieke bestandsnaam met timestamp genereren val filename = "IMG_${System.currentTimeMillis()}.jpg" val contentValues = ContentValues().apply { put(MediaStore.MediaColumns.DISPLAY_NAME, filename) put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg") // Opslaan in Pictures/CameraX map op 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 bevat de MediaStore URI onResult(results.savedUri) } override fun onError(exception: ImageCaptureException) { Log.e("PhotoCapture", "Opname mislukt: ${exception.message}") onResult(null) } } ) } } ``` CameraX 1.5 voegde DNG (RAW) opname-ondersteuning toe voor apps die onverwerkte sensordata nodig hebben. Controleer apparaatcapaciteiten met `ImageCapture.getImageCaptureCapabilities()` voordat RAW-output wordt ingeschakeld. ## Video Opnemen met VideoCapture en Recorder VideoCapture gebruikt een [Recorder](https://developer.android.com/reference/androidx/camera/video/Recorder) object voor encoding en muxing. De Recorder API volgt een prepare-start-stop patroon dat audiosynchronisatie automatisch afhandelt. ```kotlin // VideoRecordingManager.kt class VideoRecordingManager( private val context: Context, private val videoCapture: VideoCapture ) { private var activeRecording: Recording? = null fun startRecording(onEvent: (VideoRecordEvent) -> Unit): Boolean { // Controleren of al wordt opgenomen 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() // Opname voorbereiden met audio indien toestemming verleend val pendingRecording = videoCapture.output .prepareRecording(context, mediaStoreOutput) if (hasAudioPermission()) { pendingRecording.withAudioEnabled() } // Opname starten en referentie opslaan activeRecording = pendingRecording.start( ContextCompat.getMainExecutor(context) ) { event -> onEvent(event) // Referentie wissen wanneer opname voltooid 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 voegde slow-motion video-ondersteuning toe. Vraag capaciteiten op met `Recorder.getHighSpeedVideoCapabilities()` voordat 120fps of 240fps opname wordt ingeschakeld. ## CameraX met Jetpack Compose CameraX 1.5 introduceerde het `camera-compose` artifact met een `CameraXViewfinder` composable. Voor apps die nog View-gebaseerde PreviewView gebruiken, biedt AndroidView interoperabiliteit. ```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) } ) // Opnameknop overlay Row( modifier = Modifier .align(Alignment.BottomCenter) .padding(32.dp), horizontalArrangement = Arrangement.spacedBy(24.dp) ) { IconButton( onClick = { viewModel.capturePhoto() } ) { Icon(Icons.Default.Camera, "Foto maken") } IconButton( onClick = { viewModel.toggleRecording() } ) { Icon( if (viewModel.isRecording) Icons.Default.Stop else Icons.Default.Videocam, "Video opnemen" ) } } } } ``` Voor Compose-first implementaties behandelt de gids over [Jetpack Compose sollicitatievragen](/technologies/android/interview-questions/android-compose) ViewModel-integratiepatronen die direct van toepassing zijn op camera state management. ## Omgaan met Camera-permissies Android vereist CAMERA-permissie tijdens runtime. RECORD_AUDIO is alleen nodig bij video-opname met geluid. De permissiestroom moet uitleggen waarom toegang nodig is voordat deze wordt aangevraagd. ```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 Sollicitatievragen CameraX komt voor in Android-sollicitatiegesprekken bij discussies over camera-integratie, lifecycle management of hardware-abstractie. Deze vragen testen begrip van de architectuur en praktische implementatiedetails. ### Waarom CameraX gebruiken in plaats van Camera2? CameraX abstraheert apparaatspecifieke eigenaardigheden die Camera2 direct blootstelt. Een Camera2-implementatie vereist het afhandelen van honderden apparaatspecifieke workarounds. CameraX bouwt deze fixes in de bibliotheek, getest tegen het [CameraX Test Lab](https://android-developers.googleblog.com/2025/11/introducing-camerax-15-powerful-video.html) dat 150+ apparaatmodellen dekt. De lifecycle-aware binding elimineert handmatig resource management. Camera2 vereist expliciete open/close aanroepen die leaks veroorzaken wanneer niet correct afgehandeld in elke lifecycle callback. ### Hoe bindt CameraProvider use cases aan lifecycle? CameraProvider gebruikt intern het LifecycleObserver patroon. Bij het aanroepen van `bindToLifecycle()` registreert het een observer op de verstrekte LifecycleOwner. Deze observer ontvangt ON_START en ON_STOP events om de camera te openen en te sluiten. Het belangrijkste inzicht: CameraX start de camera niet direct bij binden. Het wacht tot de lifecycle de STARTED status bereikt, wat overeenkomt met de timing van Activity.onStart(). ### Wat gebeurt er bij het binden van incompatibele use cases? Niet alle use case combinaties werken op alle apparaten. Preview + VideoCapture + ImageAnalysis + ImageCapture kan falen op oudere hardware. CameraX gooit een IllegalArgumentException tijdens het binden, niet tijdens runtime. De oplossing is het controleren van `CameraProvider.hasCamera()` en apparaatcapaciteiten voordat complexe combinaties worden gebonden. Voor kritieke apps expliciet testen op low-end apparaten. ### Leg het verschil uit tussen CAPTURE_MODE_MINIMIZE_LATENCY en CAPTURE_MODE_MAXIMIZE_QUALITY MINIMIZE_LATENCY vermindert sluitervertraging door snellere verwerkingspipelines te gebruiken, mogelijk met het overslaan van nabewerking. MAXIMIZE_QUALITY past volledige HDR+-verwerking, ruisonderdrukking en multi-frame opname toe op ondersteunde apparaten. De afweging: latency-modus neemt op in 100-200ms, quality-modus kan 500ms-1s duren afhankelijk van verlichting. Sociale apps kiezen typisch voor latency. Documentscanner-apps kiezen voor quality. ### Hoe gaat CameraX om met apparaatrotatie? CameraX handelt rotatie automatisch af via de target rotation instelling. Standaard gebruikt het de Display-rotatie, maar apps kunnen dit overschrijven met `setTargetRotation()`. De EXIF-data van de outputafbeelding bevatten de correcte orientatie-tag. Voor PreviewView handelt de scaleType aspectratio-verschillen af. FILL_CENTER cropped om te vullen, FIT_CENTER toont letterboxing. De keuze hangt af van of de app prioriteit geeft aan fullscreen preview of het vermijden van cropping. ## Dependencies en Setup voor CameraX 1.6 De CameraX-bibliotheek is opgesplitst in meerdere artifacts. Voeg alleen toe wat de app gebruikt om APK-grootte te minimaliseren. ```kotlin // build.gradle.kts (Module: app) dependencies { val cameraxVersion = "1.6.2" // Core bibliotheek vereist voor alle use cases implementation("androidx.camera:camera-core:$cameraxVersion") // Camera2 implementatie (vereist) implementation("androidx.camera:camera-camera2:$cameraxVersion") // Lifecycle integratie implementation("androidx.camera:camera-lifecycle:$cameraxVersion") // VideoCapture use case implementation("androidx.camera:camera-video:$cameraxVersion") // PreviewView en camera UI componenten implementation("androidx.camera:camera-view:$cameraxVersion") // Optioneel: Extensions (Night mode, HDR, etc.) implementation("androidx.camera:camera-extensions:$cameraxVersion") // Optioneel: Realtime effecten implementation("androidx.camera:camera-effects:$cameraxVersion") } android { // CameraX vereist Java 11 bytecode compileOptions { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 } } ``` Het Manifest heeft feature declaraties en permissies nodig: ```xml ``` Gerelateerde patronen voor [Kotlin Coroutines](/blog/android/mastering-kotlin-coroutines) zijn van toepassing bij het wrappen van CameraX ListenableFuture aanroepen in suspend functies. ## Wat CameraX 1.6 Verandert voor Productie-Apps CameraX 1.6 bracht drie wijzigingen die bestaande implementaties beïnvloeden: 1. **CameraPipe backend**: De interne camera stack gebruikt nu CameraPipe, dezelfde architectuur als de Pixel camera. Dit verbetert prestaties op Pixel-apparaten en biedt een schonere basis voor geavanceerde features. Bestaande code hoeft niet te worden aangepast. 2. **Media3 Muxer standaard**: VideoCapture gebruikt nu standaard Media3 Muxer in plaats van MediaMuxer. Dit verbetert crash-bestendigheid: als de app tijdens opname stopt, blijft het videobestand afspeelbaar. Het API-oppervlak is ongewijzigd. 3. **SessionConfig API stabiel**: Apps kunnen nu geavanceerde camera-instellingen configureren via SessionConfig zonder experimentele annotaties. Dit maakt features mogelijk zoals gelijktijdig gebruik van front/back camera op ondersteunde apparaten. **Migratiepad**: Update de dependency versie. Test op apparaten die eerder problemen hadden. De [CameraX release notes](https://developer.android.com/jetpack/androidx/releases/camera) documenteren gedragswijzigingen tussen versies. - CameraX gebruikt lifecycle-aware binding: `bindToLifecycle()` verbindt use cases met zowel de camera als de Activity lifecycle - ImageCapture modi ruilen latency voor kwaliteit: kies op basis van use case, niet apparaatcapaciteit - VideoCapture vereist Recorder setup voor binding: bereid output opties voor voordat wordt gestart - Permissieafhandeling moet het doel uitleggen voor de aanvraag: vermindert weigeringspercentages - CameraX 1.6 migreerde intern naar CameraPipe: geen API-wijzigingen vereist, maar test op doelapparaten - Sollicitatievragen focussen op lifecycle management, use case combinaties en Camera2 vergelijking --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/nl/blog/android/camerax-photo-video-capture-interview-questions