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.

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 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, 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.
class CameraSetup(
private val context: Context,
private val lifecycleOwner: LifecycleOwner
) {
private lateinit var cameraProvider: ProcessCameraProvider
private var imageCapture: ImageCapture? = null
private var videoCapture: VideoCapture<Recorder>? = 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.
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 object voor encoding en muxing. De Recorder API volgt een prepare-start-stop patroon dat audiosynchronisatie automatisch afhandelt.
class VideoRecordingManager(
private val context: Context,
private val videoCapture: VideoCapture<Recorder>
) {
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.
Klaar om je Android gesprekken te halen?
Oefen met onze interactieve simulatoren, flashcards en technische tests.
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.
@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 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.
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 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.
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:
<!-- AndroidManifest.xml -->
<manifest>
<!-- Camera hardware vereiste -->
<uses-feature android:name="android.hardware.camera.any" />
<!-- Runtime permissies -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
</manifest>Gerelateerde patronen voor Kotlin Coroutines zijn van toepassing bij het wrappen van CameraX ListenableFuture aanroepen in suspend functies.
Begin met oefenen!
Test je kennis met onze gespreksimulatoren en technische tests.
Wat CameraX 1.6 Verandert voor Productie-Apps
CameraX 1.6 bracht drie wijzigingen die bestaande implementaties beïnvloeden:
-
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.
-
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.
-
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 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
Zie jij de bug in Android?
Een echt codefragment, een verborgen bug, één poging per dag. Zonder account uit te proberen.

Geschreven door
Anthony Fillion-MailletOprichter van SharpSkill
Al meer dan 10 jaar fullstack-ontwikkelaar. Hij leidt SharpSkill en staat in voor alles wat hier verschijnt.
Bijgewerkt op 11 september 2026
Delen
Gerelateerde artikelen

Android Modularisatie in 2026: Multi-Module Architectuur en Sollicitatievragen
Best practices voor Android modularisatie met convention plugins, Gradle version catalogs en feature modules. Inclusief sollicitatievragen voor senior ontwikkelaars.

Jetpack Navigation Compose in 2026: Type-Safe Navigatie en Sollicitatievragen
Een uitgebreide handleiding voor type-safe navigatie met Jetpack Compose. Praktische codevoorbeelden, best practices en veelgestelde interviewvragen voor Android-ontwikkelaars.

Android WorkManager in 2026: Achtergrondtaken, Constraints en Sollicitatievragen
Complete handleiding voor Android WorkManager 2.11/2.12 met Kotlin-codevoorbeelden, constraints-configuratie, het koppelen van werkverzoeken en veelgestelde technische sollicitatievragen.