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.

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.
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, 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.
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 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).
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 do obsługi kodowania i miksowania. API Recorder stosuje wzorzec przygotuj-rozpocznij-zatrzymaj, który automatycznie obsługuje synchronizację audio.
class VideoRecordingManager(
private val context: Context,
private val videoCapture: VideoCapture<Recorder>
) {
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.
Gotowy na rozmowy o Android?
Ćwicz z naszymi interaktywnymi symulatorami, flashcards i testami technicznymi.
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ść.
@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 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.
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, 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.
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ń:
<!-- AndroidManifest.xml -->
<manifest>
<!-- Camera hardware requirement -->
<uses-feature android:name="android.hardware.camera.any" />
<!-- Runtime permissions -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
</manifest>Powiązane wzorce dla Kotlin Coroutines mają zastosowanie przy opakowywaniu wywołań CameraX ListenableFuture w funkcje suspend.
Zacznij ćwiczyć!
Sprawdź swoją wiedzę z naszymi symulatorami rozmów i testami technicznymi.
Co CameraX 1.6 Zmienia dla Aplikacji Produkcyjnych
CameraX 1.6 wprowadził trzy zmiany wpływające na istniejące implementacje:
-
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.
-
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.
-
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 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
Znajdziesz błąd w Android?
Prawdziwy fragment kodu, ukryty błąd, jedna próba dziennie. Bez konta, żeby spróbować.

Autor:
Anthony Fillion-MailletZałożyciel SharpSkill
Programista fullstack od ponad 10 lat. Prowadzi SharpSkill i odpowiada za wszystko, co się tu ukazuje.
Zaktualizowano 11 września 2026
Udostępnij
Powiązane artykuły

Modularyzacja Androida w 2026: Architektura Multi-Module i Pytania Rekrutacyjne
Przewodnik po modularyzacji aplikacji Android w 2026. Architektura wielomodułowa, Convention Plugins, Version Catalogs i pytania na rozmowy kwalifikacyjne dla developerów Kotlin.

Jetpack Navigation Compose w 2026: Nawigacja Type-Safe i Pytania Rekrutacyjne
Kompleksowy przewodnik po Jetpack Navigation Compose z nawigacją typu type-safe, zaawansowanymi wzorcami i pytaniami rekrutacyjnymi dla programistów Android.

Android WorkManager w 2026: Zadania w Tle, Ograniczenia i Pytania Rekrutacyjne
Kompleksowy przewodnik po WorkManager 2.11 w Kotlinie - od podstawowej konfiguracji przez ograniczenia i łańcuchy zadań po testowanie i pytania na rozmowy kwalifikacyjne.