Android CameraX 2026: Foto- und Videoaufnahme mit Interview-Fragen

CameraX Tutorial für Android-Entwickler: Lifecycle-Management, Foto- und Videoaufnahme mit Jetpack Compose und Interview-Fragen.

Android CameraX 2026: Foto- und Videoaufnahme mit Interview-Fragen

Android CameraX vereinfacht die Kameraentwicklung, indem es die Hardwarekomplexität hinter einer lebenszyklusabhängigen API abstrahiert. Mit der stabilen Version 1.6.2 und der abgeschlossenen Migration zu CameraPipe liefert CameraX denselben leistungsstarken Kamera-Stack, der auch die Pixel-Kamera-App antreibt.

CameraX 1.6 Wichtige Änderungen

CameraX 1.6 migrierte zu CameraPipe, verwendet standardmäßig Media3 Muxer für VideoCapture und stabilisierte die SessionConfig-API. Die Kotlin-DSL-Builder (preview { }, imageCapture { }, videoCapture { }) reduzieren Boilerplate-Code um 40%.

CameraX-Architektur und Use-Case-Modell

CameraX stellt vier primäre Use Cases bereit, die gleichzeitig ausgeführt werden können: Preview, ImageCapture, ImageAnalysis und VideoCapture. Jeder Use Case wird an einen LifecycleOwner gebunden, sodass die Kamera automatisch mit der Activity oder dem Fragment startet und stoppt.

Der CameraProvider fungiert als Factory, die diese Use Cases instanziiert und an die Kamera bindet. Diese Entkopplung bedeutet, dass derselbe Code auf Geräten verschiedener OEMs läuft, ohne sich um herstellerspezifische Eigenheiten kümmern zu müssen.

CameraSetup.ktkotlin
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 bindet Use Cases an den Lebenszyklus
        cameraProvider = ProcessCameraProvider.getInstance(context).await()
    }
    
    fun bindUseCases(previewView: PreviewView) {
        // Bestehende Use Cases vor dem erneuten Binden lösen
        cameraProvider.unbindAll()
        
        // Preview Use Case zeigt Kamera-Feed an
        val preview = Preview.Builder()
            .build()
            .apply { setSurfaceProvider(previewView.surfaceProvider) }
        
        // ImageCapture für Fotos
        imageCapture = ImageCapture.Builder()
            .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
            .build()
        
        // VideoCapture mit Recorder
        val recorder = Recorder.Builder()
            .setQualitySelector(QualitySelector.from(Quality.FHD))
            .build()
        videoCapture = VideoCapture.withOutput(recorder)
        
        // Alle Use Cases an Lebenszyklus binden
        cameraProvider.bindToLifecycle(
            lifecycleOwner,
            CameraSelector.DEFAULT_BACK_CAMERA,
            preview,
            imageCapture,
            videoCapture
        )
    }
}

Der Aufruf von bindToLifecycle verbindet Use Cases sowohl mit der Kamera-Hardware als auch mit dem Lebenszyklus. Wenn der LifecycleOwner STARTED erreicht, öffnet sich die Kamera. Wenn er STOPPED erreicht, schließt sie sich automatisch.

Implementierung der Fotoaufnahme mit ImageCapture

ImageCapture bietet zwei Aufnahmemodi: CAPTURE_MODE_MINIMIZE_LATENCY für schnelle Auslösereaktion und CAPTURE_MODE_MAXIMIZE_QUALITY für verarbeitungsintensive Aufnahmen. Die Wahl hängt davon ab, ob die App Geschwindigkeit (Social Apps) oder Qualität (Dokumentenscanner) priorisiert.

PhotoCaptureManager.ktkotlin
class PhotoCaptureManager(
    private val context: Context,
    private val imageCapture: ImageCapture
) {
    private val mainExecutor = ContextCompat.getMainExecutor(context)
    
    fun capturePhoto(onResult: (Uri?) -> Unit) {
        // Eindeutigen Dateinamen mit Zeitstempel generieren
        val filename = "IMG_${System.currentTimeMillis()}.jpg"
        
        val contentValues = ContentValues().apply {
            put(MediaStore.MediaColumns.DISPLAY_NAME, filename)
            put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
            // In Pictures/CameraX-Ordner auf Android 10+ speichern
            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 enthält die MediaStore URI
                    onResult(results.savedUri)
                }
                
                override fun onError(exception: ImageCaptureException) {
                    Log.e("PhotoCapture", "Aufnahme fehlgeschlagen: ${exception.message}")
                    onResult(null)
                }
            }
        )
    }
}

CameraX 1.5 fügte DNG (RAW)-Aufnahmeunterstützung für Apps hinzu, die unverarbeitete Sensordaten benötigen. Die Gerätefähigkeit sollte mit ImageCapture.getImageCaptureCapabilities() geprüft werden, bevor RAW-Ausgabe aktiviert wird.

Videoaufnahme mit VideoCapture und Recorder

VideoCapture verwendet ein Recorder-Objekt zur Handhabung von Encoding und Muxing. Die Recorder-API folgt einem Prepare-Start-Stop-Muster, das die Audio-Synchronisation automatisch handhabt.

VideoRecordingManager.ktkotlin
class VideoRecordingManager(
    private val context: Context,
    private val videoCapture: VideoCapture<Recorder>
) {
    private var activeRecording: Recording? = null
    
    fun startRecording(onEvent: (VideoRecordEvent) -> Unit): Boolean {
        // Prüfen ob bereits aufgenommen wird
        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()
        
        // Aufnahme mit Audio vorbereiten falls Berechtigung erteilt
        val pendingRecording = videoCapture.output
            .prepareRecording(context, mediaStoreOutput)
        
        if (hasAudioPermission()) {
            pendingRecording.withAudioEnabled()
        }
        
        // Aufnahme starten und Referenz speichern
        activeRecording = pendingRecording.start(
            ContextCompat.getMainExecutor(context)
        ) { event ->
            onEvent(event)
            
            // Referenz löschen wenn Aufnahme abgeschlossen
            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 fügte Zeitlupen-Videoaufnahme hinzu. Die Fähigkeiten sollten mit Recorder.getHighSpeedVideoCapabilities() abgefragt werden, bevor 120fps oder 240fps Aufnahme aktiviert wird.

Bereit für deine Android-Interviews?

Übe mit unseren interaktiven Simulatoren, Flashcards und technischen Tests.

CameraX mit Jetpack Compose

CameraX 1.5 führte das camera-compose-Artefakt mit einem CameraXViewfinder-Composable ein. Für Apps, die noch das View-basierte PreviewView verwenden, bietet AndroidView Interoperabilität.

CameraPreviewComposable.ktkotlin
@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)
            }
        )
        
        // Aufnahme-Buttons Overlay
        Row(
            modifier = Modifier
                .align(Alignment.BottomCenter)
                .padding(32.dp),
            horizontalArrangement = Arrangement.spacedBy(24.dp)
        ) {
            IconButton(
                onClick = { viewModel.capturePhoto() }
            ) {
                Icon(Icons.Default.Camera, "Foto aufnehmen")
            }
            
            IconButton(
                onClick = { viewModel.toggleRecording() }
            ) {
                Icon(
                    if (viewModel.isRecording) Icons.Default.Stop
                    else Icons.Default.Videocam,
                    "Video aufnehmen"
                )
            }
        }
    }
}

Für Compose-First-Implementierungen behandelt der Leitfaden zu Jetpack Compose Interview-Fragen ViewModel-Integrationsmuster, die direkt auf die Kamera-Zustandsverwaltung anwendbar sind.

Handhabung von Kamera-Berechtigungen

Android erfordert die CAMERA-Berechtigung zur Laufzeit. RECORD_AUDIO wird nur benötigt, wenn Video mit Ton aufgenommen wird. Der Berechtigungsablauf sollte erklären, warum der Zugriff benötigt wird, bevor er angefordert wird.

PermissionHandler.ktkotlin
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-Fragen

CameraX erscheint in Android-Interviews bei Diskussionen über Kamera-Integration, Lifecycle-Management oder Hardware-Abstraktion. Diese Fragen testen das Verständnis der Architektur und praktische Implementierungsdetails.

Warum CameraX anstelle von Camera2 verwenden?

CameraX abstrahiert gerätespezifische Eigenheiten, die Camera2 direkt exponiert. Eine Camera2-Implementierung erfordert die Handhabung hunderter gerätespezifischer Workarounds. CameraX baut diese Korrekturen in die Bibliothek ein, getestet gegen das CameraX Test Lab, das über 150 Gerätemodelle abdeckt.

Die lebenszyklusabhängige Bindung eliminiert manuelles Ressourcenmanagement. Camera2 erfordert explizite Open/Close-Aufrufe, die zu Leaks führen, wenn sie nicht in jedem Lifecycle-Callback korrekt behandelt werden.

Wie bindet CameraProvider Use Cases an den Lebenszyklus?

CameraProvider verwendet intern das LifecycleObserver-Pattern. Beim Aufruf von bindToLifecycle() registriert es einen Observer am bereitgestellten LifecycleOwner. Dieser Observer empfängt ON_START- und ON_STOP-Events zum Öffnen und Schließen der Kamera.

Die Schlüsselerkenntnis: CameraX startet die Kamera nicht sofort beim Binden. Es wartet, bis der Lebenszyklus den STARTED-Zustand erreicht, was dem Timing von Activity.onStart() entspricht.

Was passiert beim Binden inkompatibler Use Cases?

Nicht alle Use-Case-Kombinationen funktionieren auf allen Geräten. Preview + VideoCapture + ImageAnalysis + ImageCapture kann auf älterer Hardware fehlschlagen. CameraX wirft eine IllegalArgumentException zur Bind-Zeit, nicht zur Laufzeit.

Die Lösung besteht darin, CameraProvider.hasCamera() und Gerätefähigkeiten zu prüfen, bevor komplexe Kombinationen gebunden werden. Für kritische Apps sollte explizit auf Low-End-Geräten getestet werden.

Den Unterschied zwischen CAPTURE_MODE_MINIMIZE_LATENCY und CAPTURE_MODE_MAXIMIZE_QUALITY erklären

MINIMIZE_LATENCY reduziert die Auslöseverzögerung durch schnellere Verarbeitungspipelines, möglicherweise unter Überspringen einiger Nachbearbeitung. MAXIMIZE_QUALITY wendet vollständige HDR+-Verarbeitung, Rauschunterdrückung und Multi-Frame-Aufnahme auf unterstützten Geräten an.

Der Kompromiss: Latenz-Modus erfasst in 100-200ms, Qualitätsmodus kann 500ms-1s dauern, abhängig von der Beleuchtung. Social Apps wählen typischerweise Latenz. Dokumentenscanner-Apps wählen Qualität.

Wie handhabt CameraX Geräterotation?

CameraX handhabt Rotation automatisch durch die Zielrotations-Einstellung. Standardmäßig verwendet es die Display-Rotation, aber Apps können mit setTargetRotation() überschreiben. Die EXIF-Daten des Ausgabebilds enthalten das korrekte Orientierungs-Tag.

Für PreviewView handhabt der scaleType Seitenverhältnis-Unterschiede. FILL_CENTER beschneidet zum Füllen, FIT_CENTER zeigt Letterboxing. Die Wahl hängt davon ab, ob die App Vollbild-Vorschau oder Vermeidung von Beschneidung priorisiert.

Abhängigkeiten und Setup für CameraX 1.6

Die CameraX-Bibliothek ist in mehrere Artefakte aufgeteilt. Es sollte nur eingebunden werden, was die App verwendet, um die APK-Größe zu minimieren.

build.gradle.kts (Module: app)kotlin
dependencies {
    val cameraxVersion = "1.6.2"
    
    // Core-Bibliothek für alle Use Cases erforderlich
    implementation("androidx.camera:camera-core:$cameraxVersion")
    
    // Camera2-Implementierung (erforderlich)
    implementation("androidx.camera:camera-camera2:$cameraxVersion")
    
    // Lifecycle-Integration
    implementation("androidx.camera:camera-lifecycle:$cameraxVersion")
    
    // VideoCapture Use Case
    implementation("androidx.camera:camera-video:$cameraxVersion")
    
    // PreviewView und Kamera-UI-Komponenten
    implementation("androidx.camera:camera-view:$cameraxVersion")
    
    // Optional: Extensions (Nachtmodus, HDR, etc.)
    implementation("androidx.camera:camera-extensions:$cameraxVersion")
    
    // Optional: Echtzeit-Effekte
    implementation("androidx.camera:camera-effects:$cameraxVersion")
}

android {
    // CameraX erfordert Java 11 Bytecode
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    }
}

Das Manifest benötigt Feature-Deklarationen und Berechtigungen:

xml
<!-- AndroidManifest.xml -->
<manifest>
    <!-- Kamera-Hardware-Anforderung -->
    <uses-feature android:name="android.hardware.camera.any" />
    
    <!-- Laufzeit-Berechtigungen -->
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
</manifest>

Verwandte Muster für Kotlin Coroutines gelten beim Wrapping von CameraX ListenableFuture-Aufrufen in Suspend-Funktionen.

Fang an zu üben!

Teste dein Wissen mit unseren Interview-Simulatoren und technischen Tests.

Was CameraX 1.6 für Produktions-Apps ändert

CameraX 1.6 brachte drei Änderungen, die bestehende Implementierungen betreffen:

  1. CameraPipe-Backend: Der interne Kamera-Stack verwendet jetzt CameraPipe, dieselbe Architektur wie die Pixel-Kamera. Dies verbessert die Leistung auf Pixel-Geräten und bietet eine sauberere Grundlage für erweiterte Funktionen. Bestehender Code muss nicht geändert werden.

  2. Media3 Muxer Standard: VideoCapture verwendet jetzt standardmäßig Media3 Muxer anstelle von MediaMuxer. Dies verbessert die Absturz-Resilienz: Wenn die App während der Aufnahme terminiert, bleibt die Videodatei abspielbar. Die API-Oberfläche ist unverändert.

  3. SessionConfig API stabil: Apps können jetzt erweiterte Kameraeinstellungen über SessionConfig ohne experimentelle Annotationen konfigurieren. Dies ermöglicht Funktionen wie gleichzeitige Nutzung von Front- und Rückkamera auf unterstützten Geräten.

Migrationspfad: Die Dependency-Version aktualisieren. Auf Geräten testen, die zuvor Probleme hatten. Die CameraX Release Notes dokumentieren Verhaltensänderungen zwischen Versionen.

  • CameraX verwendet lebenszyklusabhängige Bindung: bindToLifecycle() verbindet Use Cases sowohl mit der Kamera als auch mit dem Activity-Lebenszyklus
  • ImageCapture-Modi tauschen Latenz gegen Qualität: Wahl basierend auf Use Case, nicht Gerätefähigkeit
  • VideoCapture erfordert Recorder-Setup vor dem Binden: Output-Optionen vor dem Start vorbereiten
  • Berechtigungsbehandlung sollte den Zweck vor der Anfrage erklären: reduziert Ablehnungsraten
  • CameraX 1.6 migrierte intern zu CameraPipe: keine API-Änderungen erforderlich, aber auf Zielgeräten testen
  • Interview-Fragen fokussieren auf Lifecycle-Management, Use-Case-Kombinationen und Camera2-Vergleich
Tägliche Challenge

Findest du den Bug in Android?

Ein echter Codeausschnitt, ein versteckter Bug, ein Versuch pro Tag. Zum Ausprobieren ohne Konto.

Anthony Fillion-Maillet

Geschrieben von

Anthony Fillion-Maillet

Gründer von SharpSkill

Seit über 10 Jahren Fullstack-Entwickler. Er leitet SharpSkill und verantwortet alles, was hier erscheint.

Aktualisiert am 11. September 2026

Teilen

Verwandte Artikel