Video-Aufnahme auf Android: Lifecycle, Permissions und Speicher
Android bietet mit CameraX eine moderne API für Video-Aufnahmen. Du lernst, Lifecycle, Berechtigungen und Dateispeicher sicher einzusetzen.
Video-Aufnahme gehört zu den anspruchsvollsten Gerätezugriffen auf Android. Kamera, Mikrofon, Lifecycle und Speicher greifen direkt ineinander — ein einziger Fehler im Ablauf führt zu Abstürzen, Ressourcen-Leaks oder kaputten Mediendateien. Wer versteht, wie die drei Säulen Berechtigungen, Lifecycle-Management und Dateispeicherung zusammenhängen, schreibt robuste Aufnahme-Features, die auch auf Einsteiger-Hardware zuverlässig funktionieren.
Was ist das?
Video-Aufnahme bedeutet auf Android: Kameradaten und Audiodaten werden synchron erfasst, in ein Containerformat kodiert — typischerweise MPEG-4 — und als Datei auf dem Gerät gespeichert. Aus Sicht der Architektur ist das ein Datenpipeline-Problem: Sensordaten fließen durch einen Codec und landen schließlich im Dateisystem.
Android kennt zwei Herangehensweisen. Der einfachste Weg ist der Intent-basierte Ansatz: Du forderst die System-Kamera-App über MediaStore.ACTION_VIDEO_CAPTURE an, sie übernimmt die gesamte Aufnahme und liefert dir einen URI zurück. Dieser Ansatz reicht für einfache Szenarien, gibt dir aber keine Kontrolle über Qualität, Dauer oder UI.
Sobald du das Aufnahme-Erlebnis selbst gestalten willst, greifst du zur CameraX-API. CameraX ist eine Jetpack-Bibliothek und Googles offiziell empfohlene Kamera-Abstraktionsschicht. Sie kapselt die Hardware-Unterschiede zwischen tausenden Android-Geräten und bietet den VideoCapture-Use-Case als Einstiegspunkt für programmatische Video-Aufnahme.
Im Roadmap-Kontext steht Video-Aufnahme in Phase 9 — Platform APIs and Device Capabilities. Du hast bis hierher Permissions, Lifecycle und das Dateisystem als einzelne Themen kennengelernt. Video-Aufnahme ist die Nagelprobe: Alle drei kommen gleichzeitig zum Einsatz.
Wie funktioniert es?
Berechtigungen
Vor jedem Kamerazugriff brauchst du zwei Laufzeit-Berechtigungen im Manifest:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
Auf Android 9 und älter ist zusätzlich WRITE_EXTERNAL_STORAGE nötig, wenn du in den externen Speicher schreibst. Ab Android 10 entfällt das für den Schreibzugriff über MediaStore. Frage beide Berechtigungen mit ActivityResultContracts.RequestMultiplePermissions an, bevor du den ProcessCameraProvider initialisierst — sonst wirft CameraX eine CameraAccessException und deine App stürzt ab, ohne dem Nutzer eine verständliche Fehlermeldung zu geben.
CameraX VideoCapture-Use-Case
CameraX arbeitet mit Use-Cases. Für Video bindest du Preview und VideoCapture<Recorder> gemeinsam an den Lifecycle:
val cameraProviderFuture = ProcessCameraProvider.getInstance(context)
cameraProviderFuture.addListener({
val cameraProvider = cameraProviderFuture.get()
val preview = Preview.Builder().build().also {
it.setSurfaceProvider(viewBinding.viewFinder.surfaceProvider)
}
val recorder = Recorder.Builder()
.setQualitySelector(QualitySelector.from(Quality.HD))
.build()
val videoCapture = VideoCapture.withOutput(recorder)
cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(
this, // LifecycleOwner
CameraSelector.DEFAULT_BACK_CAMERA,
preview,
videoCapture
)
}, ContextCompat.getMainExecutor(context))
Der entscheidende Parameter ist der LifecycleOwner. CameraX registriert sich als Lifecycle-Observer und gibt den Kamera-Stream automatisch frei, wenn die Activity in STOPPED übergeht. Du musst keine onStop- oder onDestroy-Logik mehr von Hand schreiben — solange du bindToLifecycle korrekt verwendest.
Aufnahme starten und stoppen
Eine Aufnahme startest du über das Recorder-Objekt und speicherst direkt in MediaStore:
val contentValues = ContentValues().apply {
put(MediaStore.Video.Media.DISPLAY_NAME, "aufnahme_${System.currentTimeMillis()}.mp4")
put(MediaStore.Video.Media.MIME_TYPE, "video/mp4")
put(MediaStore.Video.Media.RELATIVE_PATH, "Movies/MeineApp")
}
val mediaStoreOutput = MediaStoreOutputOptions
.Builder(contentResolver, MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
.setContentValues(contentValues)
.build()
val recording = videoCapture.output
.prepareRecording(context, mediaStoreOutput)
.withAudioEnabled()
.start(ContextCompat.getMainExecutor(context)) { event ->
if (event is VideoRecordEvent.Finalize) {
if (!event.hasError()) {
val uri = event.outputResults.outputUri
// Datei ist vollständig und im MediaStore indiziert
}
}
}
// Zum Stoppen:
recording.stop()
MediaStoreOutputOptions schreibt die Datei direkt in MediaStore.Video.Media, sodass sie sofort in der Galerie sichtbar ist und eine App-Deinstallation überlebt.
In der Praxis
Häufige Stolperfalle: Aufnahme nicht gestoppt
Der klassische Fehler: Die Aufnahme läuft, der Nutzer drückt Home, die Activity wechselt in den Hintergrund. Ohne korrekte Lifecycle-Behandlung hält CameraX den Kamera-Stream offen — auf vielen Geräten leuchtet dann dauerhaft das Kamera-Indikatorlicht, und die MP4-Datei wird nie korrekt finalisiert; sie ist anschließend nicht abspielbar.
CameraX löst das automatisch, wenn du bindToLifecycle mit einem regulären LifecycleOwner nutzt. Wenn du jedoch einen Custom-Lifecycle oder einen ProcessLifecycleOwner verwendest, musst du in onStop explizit recording.stop() aufrufen und sicherstellen, dass der Finalize-Event verarbeitet wird, bevor du die Activity verlässt.
Speicher: Intern ist keine Option für Videos
Videos können schnell mehrere Hundert Megabyte groß werden. Der interne App-Speicher (filesDir) ist begrenzt, wird nicht im Mediensystem indiziert und ist für andere Apps nicht zugänglich. Schreibe Videodateien immer über MediaStoreOutputOptions in den externen Medienspeicher. Auf Android 10 und neuer brauchst du dafür keine WRITE_EXTERNAL_STORAGE-Berechtigung — MediaStore übernimmt die Zugriffskontrolle. Das ist sicherer im Sinne der Android-Security-Best-Practices und reduziert den Bedarf an sensitiven Berechtigungen in deiner App.
Qualität mit Fallback-Strategie wählen
val qualitySelector = QualitySelector.fromOrderedList(
listOf(Quality.UHD, Quality.FHD, Quality.HD),
FallbackStrategy.lowerQualityOrHigherThan(Quality.SD)
)
Mit fromOrderedList und einer FallbackStrategy gibst du CameraX eine Präferenzliste. Auf Low-End-Geräten ohne UHD-Support fällt es automatisch auf die nächstbeste Qualität zurück — kein Crash, kein lautloser Fehler, kein leerer Bildschirm.
Fazit
Video-Aufnahme auf Android ist mehr als ein einzelner API-Aufruf: Sie verbindet Berechtigungsmanagement, Lifecycle-Bewusstsein und Dateisystem-Strategie zu einem einzigen Feature. CameraX nimmt dir die hardware-spezifischen Eigenheiten ab, aber du musst die Konzepte dahinter verstehen, damit deine App auf unterschiedlichen Geräten und in verschiedenen Lifecycle-Zuständen korrekt funktioniert. Schreibe als nächsten Schritt eine kleine Demo-App, die eine Aufnahme startet, die Activity anschließend in den Hintergrund schickt und dann überprüft, ob die fertige Datei vollständig und abspielbar im MediaStore landet — dieser manuelle Test deckt die häufigsten Integrationsfehler auf, lange bevor sie im Play Store auftauchen.