# Android CameraX w 2026: Przechwytywanie Zdjęć i Wideo z Pytaniami Rekrutacyjnymi > Poradnik Android CameraX 1.6 obejmujący przypadki użycia Preview, ImageCapture i VideoCapture. Zawiera kod Kotlin, integrację z Compose oraz pytania rekrutacyjne. - Published: 2026-09-11 - Updated: 2026-09-11 - Author: Anthony Fillion-Maillet - Reading time: 5 min --- Android CameraX upraszcza programowanie kamery poprzez abstrakcję złożoności sprzętowej za pomocą API świadomego cyklu życia. W wersji 1.6.2, która jest teraz stabilna, oraz po zakończeniu migracji do CameraPipe, CameraX dostarcza ten sam wydajny stos kamery, który zasila aplikację aparatu Pixel. > **Kluczowe Zmiany w CameraX 1.6** > > CameraX 1.6 przeprowadził migrację do CameraPipe, domyślnie używa Media3 Muxer dla VideoCapture oraz ustabilizował API SessionConfig. Kotlin DSL builders (`preview { }`, `imageCapture { }`, `videoCapture { }`) redukują kod szablonowy o 40%. ## Architektura CameraX i Model Przypadków Użycia CameraX udostępnia cztery główne przypadki użycia, które mogą działać jednocześnie: Preview, ImageCapture, ImageAnalysis oraz VideoCapture. Każdy przypadek użycia wiąże się z [LifecycleOwner](https://developer.android.com/topic/libraries/architecture/lifecycle), więc kamera automatycznie uruchamia się i zatrzymuje wraz z aktywnością lub fragmentem. CameraProvider działa jako fabryka, która tworzy instancje tych przypadków użycia i wiąże je z kamerą. To rozdzielenie oznacza, że ten sam kod działa na urządzeniach różnych producentów bez martwienia się o specyficzne dziwactwa dostawców. ```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 binds use cases to lifecycle cameraProvider = ProcessCameraProvider.getInstance(context).await() } fun bindUseCases(previewView: PreviewView) { // Unbind existing use cases before rebinding cameraProvider.unbindAll() // Preview use case displays camera feed val preview = Preview.Builder() .build() .apply { setSurfaceProvider(previewView.surfaceProvider) } // ImageCapture for photos imageCapture = ImageCapture.Builder() .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) .build() // VideoCapture with Recorder val recorder = Recorder.Builder() .setQualitySelector(QualitySelector.from(Quality.FHD)) .build() videoCapture = VideoCapture.withOutput(recorder) // Bind all use cases to lifecycle cameraProvider.bindToLifecycle( lifecycleOwner, CameraSelector.DEFAULT_BACK_CAMERA, preview, imageCapture, videoCapture ) } } ``` Wywołanie `bindToLifecycle` łączy przypadki użycia zarówno ze sprzętem kamery, jak i cyklem życia. Gdy LifecycleOwner wchodzi w stan STARTED, kamera się otwiera. Gdy wchodzi w stan STOPPED, kamera automatycznie się zamyka. ## Implementacja Przechwytywania Zdjęć z ImageCapture ImageCapture oferuje dwa tryby przechwytywania: `CAPTURE_MODE_MINIMIZE_LATENCY` dla szybkiej reakcji migawki oraz `CAPTURE_MODE_MAXIMIZE_QUALITY` dla zdjęć wymagających intensywnego przetwarzania. Wybór zależy od tego, czy aplikacja priorytetyzuje szybkość (aplikacje społecznościowe) czy jakość (skanery dokumentów). ```kotlin // PhotoCaptureManager.kt class PhotoCaptureManager( private val context: Context, private val imageCapture: ImageCapture ) { private val mainExecutor = ContextCompat.getMainExecutor(context) fun capturePhoto(onResult: (Uri?) -> Unit) { // Generate unique filename with timestamp val filename = "IMG_${System.currentTimeMillis()}.jpg" val contentValues = ContentValues().apply { put(MediaStore.MediaColumns.DISPLAY_NAME, filename) put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg") // Store in Pictures/CameraX folder on 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 contains the MediaStore URI onResult(results.savedUri) } override fun onError(exception: ImageCaptureException) { Log.e("PhotoCapture", "Capture failed: ${exception.message}") onResult(null) } } ) } } ``` CameraX 1.5 dodał obsługę przechwytywania DNG (RAW) dla aplikacji wymagających nieprzetworzonych danych z sensora. Należy sprawdzić możliwości urządzenia za pomocą `ImageCapture.getImageCaptureCapabilities()` przed włączeniem wyjścia RAW. ## Nagrywanie Wideo z VideoCapture i Recorder VideoCapture używa obiektu [Recorder](https://developer.android.com/reference/androidx/camera/video/Recorder) do obsługi kodowania i miksowania. API Recorder stosuje wzorzec przygotuj-rozpocznij-zatrzymaj, który automatycznie obsługuje synchronizację 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 { // Check if already recording 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() // Prepare recording with audio if permission granted val pendingRecording = videoCapture.output .prepareRecording(context, mediaStoreOutput) if (hasAudioPermission()) { pendingRecording.withAudioEnabled() } // Start recording and store reference activeRecording = pendingRecording.start( ContextCompat.getMainExecutor(context) ) { event -> onEvent(event) // Clear reference when recording completes 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 dodał obsługę nagrywania wideo w zwolnionym tempie. Należy sprawdzić możliwości za pomocą `Recorder.getHighSpeedVideoCapabilities()` przed włączeniem nagrywania 120fps lub 240fps. ## CameraX z Jetpack Compose CameraX 1.5 wprowadził artefakt `camera-compose` z kompozytorem `CameraXViewfinder`. Dla aplikacji nadal używających PreviewView opartego na widokach, AndroidView zapewnia interoperacyjność. ```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) } ) // Capture buttons overlay Row( modifier = Modifier .align(Alignment.BottomCenter) .padding(32.dp), horizontalArrangement = Arrangement.spacedBy(24.dp) ) { IconButton( onClick = { viewModel.capturePhoto() } ) { Icon(Icons.Default.Camera, "Take photo") } IconButton( onClick = { viewModel.toggleRecording() } ) { Icon( if (viewModel.isRecording) Icons.Default.Stop else Icons.Default.Videocam, "Record video" ) } } } } ``` Dla implementacji opartych na Compose, przewodnik [pytań rekrutacyjnych Jetpack Compose](/technologies/android/interview-questions/android-compose) obejmuje wzorce integracji ViewModel, które mają bezpośrednie zastosowanie w zarządzaniu stanem kamery. ## Obsługa Uprawnień Kamery Android wymaga uprawnienia CAMERA w czasie wykonywania. RECORD_AUDIO jest potrzebne tylko podczas nagrywania wideo z dźwiękiem. Przepływ uprawnień powinien wyjaśniać, dlaczego dostęp jest potrzebny, przed zażądaniem. ```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) } } } ``` ## Pytania Rekrutacyjne CameraX CameraX pojawia się na rozmowach kwalifikacyjnych Android podczas omawiania integracji kamery, zarządzania cyklem życia lub abstrakcji sprzętowej. Te pytania testują zrozumienie architektury i praktycznych szczegółów implementacji. ### Dlaczego używać CameraX zamiast Camera2? CameraX abstrahuje specyficzne dla urządzeń dziwactwa, które Camera2 eksponuje bezpośrednio. Implementacja Camera2 wymaga obsługi setek obejść specyficznych dla urządzeń. CameraX wbudowuje te poprawki w bibliotekę, testowaną na [CameraX Test Lab](https://android-developers.googleblog.com/2025/11/introducing-camerax-15-powerful-video.html), który obejmuje ponad 150 modeli urządzeń. Wiązanie świadome cyklu życia eliminuje ręczne zarządzanie zasobami. Camera2 wymaga jawnych wywołań open/close, które powodują wycieki, gdy nie są poprawnie obsługiwane w każdym wywołaniu zwrotnym cyklu życia. ### Jak CameraProvider wiąże przypadki użycia z cyklem życia? CameraProvider wewnętrznie używa wzorca LifecycleObserver. Podczas wywoływania `bindToLifecycle()` rejestruje obserwatora na dostarczonym LifecycleOwner. Ten obserwator otrzymuje zdarzenia ON_START i ON_STOP, aby otwierać i zamykać kamerę. Kluczowa uwaga: CameraX nie uruchamia kamery natychmiast po wiązaniu. Czeka, aż cykl życia osiągnie stan STARTED, co odpowiada czasowi Activity.onStart(). ### Co się dzieje, gdy wiążemy niekompatybilne przypadki użycia? Nie wszystkie kombinacje przypadków użycia działają na wszystkich urządzeniach. Preview + VideoCapture + ImageAnalysis + ImageCapture może nie działać na starszym sprzęcie. CameraX wyrzuca IllegalArgumentException w momencie wiązania, a nie w czasie wykonywania. Rozwiązaniem jest sprawdzanie `CameraProvider.hasCamera()` i możliwości urządzenia przed wiązaniem złożonych kombinacji. Dla krytycznych aplikacji należy jawnie testować na urządzeniach z niższej półki. ### Wyjaśnij różnicę między CAPTURE_MODE_MINIMIZE_LATENCY a CAPTURE_MODE_MAXIMIZE_QUALITY MINIMIZE_LATENCY redukuje opóźnienie migawki poprzez użycie szybszych potoków przetwarzania, potencjalnie pomijając niektóre post-przetwarzanie. MAXIMIZE_QUALITY stosuje pełne przetwarzanie HDR+, redukcję szumów i przechwytywanie wieloklatkowe na obsługiwanych urządzeniach. Kompromis: tryb opóźnienia przechwytuje w 100-200ms, tryb jakości może zająć 500ms-1s w zależności od oświetlenia. Aplikacje społecznościowe zazwyczaj wybierają opóźnienie. Aplikacje do skanowania dokumentów wybierają jakość. ### Jak CameraX obsługuje rotację urządzenia? CameraX automatycznie obsługuje rotację poprzez ustawienie docelowej rotacji. Domyślnie używa rotacji wyświetlacza, ale aplikacje mogą nadpisać za pomocą `setTargetRotation()`. Dane EXIF obrazu wyjściowego zawierają poprawny tag orientacji. Dla PreviewView, scaleType obsługuje różnice proporcji. FILL_CENTER przycina, aby wypełnić, FIT_CENTER pokazuje letterboxing. Wybór zależy od tego, czy aplikacja priorytetyzuje podgląd pełnoekranowy czy unikanie przycinania. ## Zależności i Konfiguracja dla CameraX 1.6 Biblioteka CameraX jest podzielona na wiele artefaktów. Należy dołączyć tylko to, czego aplikacja używa, aby zminimalizować rozmiar APK. ```kotlin // build.gradle.kts (Module: app) dependencies { val cameraxVersion = "1.6.2" // Core library required for all use cases implementation("androidx.camera:camera-core:$cameraxVersion") // Camera2 implementation (required) implementation("androidx.camera:camera-camera2:$cameraxVersion") // Lifecycle integration implementation("androidx.camera:camera-lifecycle:$cameraxVersion") // VideoCapture use case implementation("androidx.camera:camera-video:$cameraxVersion") // PreviewView and camera UI components implementation("androidx.camera:camera-view:$cameraxVersion") // Optional: Extensions (Night mode, HDR, etc.) implementation("androidx.camera:camera-extensions:$cameraxVersion") // Optional: Real-time effects implementation("androidx.camera:camera-effects:$cameraxVersion") } android { // CameraX requires Java 11 bytecode compileOptions { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 } } ``` Manifest wymaga deklaracji funkcji i uprawnień: ```xml ``` Powiązane wzorce dla [Kotlin Coroutines](/blog/android/mastering-kotlin-coroutines) mają zastosowanie przy opakowywaniu wywołań CameraX ListenableFuture w funkcje suspend. ## Co CameraX 1.6 Zmienia dla Aplikacji Produkcyjnych CameraX 1.6 wprowadził trzy zmiany wpływające na istniejące implementacje: 1. **Backend CameraPipe**: Wewnętrzny stos kamery teraz używa CameraPipe, tej samej architektury co kamera Pixel. Poprawia to wydajność na urządzeniach Pixel i zapewnia czystszą podstawę dla zaawansowanych funkcji. Istniejący kod nie wymaga zmian. 2. **Domyślny Media3 Muxer**: VideoCapture teraz używa Media3 Muxer zamiast MediaMuxer. Poprawia to odporność na awarie: jeśli aplikacja zostanie zakończona podczas nagrywania, plik wideo pozostaje odtwarzalny. Powierzchnia API pozostaje niezmieniona. 3. **Stabilne API SessionConfig**: Aplikacje mogą teraz konfigurować zaawansowane ustawienia kamery przez SessionConfig bez adnotacji eksperymentalnych. Umożliwia to funkcje takie jak jednoczesne użycie kamery przedniej i tylnej na obsługiwanych urządzeniach. **Ścieżka migracji**: Zaktualizuj wersję zależności. Przetestuj na urządzeniach, które wcześniej miały problemy. [Notatki wydania CameraX](https://developer.android.com/jetpack/androidx/releases/camera) dokumentują wszelkie zmiany behawioralne między wersjami. - CameraX używa wiązania świadomego cyklu życia: `bindToLifecycle()` łączy przypadki użycia zarówno z kamerą, jak i cyklem życia Activity - Tryby ImageCapture wymieniają opóźnienie na jakość: wybierz na podstawie przypadku użycia, a nie możliwości urządzenia - VideoCapture wymaga konfiguracji Recorder przed wiązaniem: przygotuj opcje wyjścia przed rozpoczęciem - Obsługa uprawnień powinna wyjaśniać cel przed żądaniem: zmniejsza wskaźnik odrzuceń - CameraX 1.6 wewnętrznie przeprowadził migrację do CameraPipe: nie są wymagane zmiany API, ale testuj na docelowych urządzeniach - Pytania rekrutacyjne koncentrują się na zarządzaniu cyklem życia, kombinacjach przypadków użycia i porównaniu z Camera2 --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/pl/blog/android/camerax-photo-video-capture-interview-questions