Android CameraX у 2026: Захоплення Фото та Відео з Питаннями для Співбесід
Посібник з Android CameraX 1.6, що охоплює випадки використання Preview, ImageCapture та VideoCapture. Містить код Kotlin, інтеграцію з Compose та питання для співбесід.

Android CameraX спрощує розробку камери шляхом абстрагування апаратної складності за допомогою API, що враховує життєвий цикл. З версією 1.6.2, яка тепер стабільна, та завершеною міграцією на CameraPipe, CameraX надає той самий високопродуктивний стек камери, що живить додаток камери Pixel.
CameraX 1.6 мігрував на CameraPipe, за замовчуванням використовує Media3 Muxer для VideoCapture та стабілізував API SessionConfig. Kotlin DSL builders (preview { }, imageCapture { }, videoCapture { }) зменшують шаблонний код на 40%.
Архітектура CameraX та Модель Випадків Використання
CameraX надає чотири основні випадки використання, які можуть працювати одночасно: Preview, ImageCapture, ImageAnalysis та VideoCapture. Кожен випадок використання прив'язується до LifecycleOwner, тому камера автоматично запускається та зупиняється разом з activity або fragment.
CameraProvider діє як фабрика, що створює екземпляри цих випадків використання та прив'язує їх до камери. Це розділення означає, що той самий код працює на пристроях різних виробників без турботи про специфічні особливості постачальників.
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
)
}
}Виклик bindToLifecycle з'єднує випадки використання як з апаратним забезпеченням камери, так і з життєвим циклом. Коли LifecycleOwner входить у стан STARTED, камера відкривається. Коли входить у стан STOPPED, камера автоматично закривається.
Реалізація Захоплення Фото з ImageCapture
ImageCapture пропонує два режими захоплення: CAPTURE_MODE_MINIMIZE_LATENCY для швидкої реакції затвора та CAPTURE_MODE_MAXIMIZE_QUALITY для знімків з інтенсивною обробкою. Вибір залежить від того, чи додаток пріоритезує швидкість (соціальні додатки) чи якість (сканери документів).
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 додав підтримку захоплення DNG (RAW) для додатків, що потребують необроблених даних сенсора. Перевірте можливості пристрою за допомогою ImageCapture.getImageCaptureCapabilities() перед увімкненням виводу RAW.
Запис Відео з VideoCapture та Recorder
VideoCapture використовує об'єкт Recorder для обробки кодування та мікшування. API Recorder дотримується шаблону підготувати-почати-зупинити, який автоматично обробляє синхронізацію аудіо.
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 додав підтримку уповільненого відео. Запитуйте можливості за допомогою Recorder.getHighSpeedVideoCapabilities() перед увімкненням запису 120fps або 240fps.
Готовий до співбесід з Android?
Практикуйся з нашими інтерактивними симуляторами, flashcards та технічними тестами.
CameraX з Jetpack Compose
CameraX 1.5 представив артефакт camera-compose з composable CameraXViewfinder. Для додатків, що досі використовують PreviewView на основі View, AndroidView забезпечує сумісність.
@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"
)
}
}
}
}Для реалізацій на основі Compose, посібник питань для співбесід Jetpack Compose охоплює шаблони інтеграції ViewModel, що безпосередньо застосовуються до керування станом камери.
Обробка Дозволів Камери
Android вимагає дозволу CAMERA під час виконання. RECORD_AUDIO потрібен лише при записі відео зі звуком. Потік дозволів повинен пояснювати, чому потрібен доступ, перед запитом.
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
CameraX з'являється на співбесідах Android при обговоренні інтеграції камери, керування життєвим циклом або апаратної абстракції. Ці питання тестують розуміння архітектури та практичних деталей реалізації.
Чому використовувати CameraX замість Camera2?
CameraX абстрагує специфічні для пристроїв особливості, які Camera2 експонує безпосередньо. Реалізація Camera2 вимагає обробки сотень специфічних для пристроїв обхідних рішень. CameraX вбудовує ці виправлення в бібліотеку, тестовану на CameraX Test Lab, що охоплює понад 150 моделей пристроїв.
Прив'язка, що враховує життєвий цикл, усуває ручне керування ресурсами. Camera2 вимагає явних викликів open/close, які спричиняють витоки, якщо не обробляються правильно в кожному зворотному виклику життєвого циклу.
Як CameraProvider прив'язує випадки використання до життєвого циклу?
CameraProvider внутрішньо використовує шаблон LifecycleObserver. При виклику bindToLifecycle() реєструє спостерігача на наданому LifecycleOwner. Цей спостерігач отримує події ON_START та ON_STOP для відкриття та закриття камери.
Ключовий момент: CameraX не запускає камеру негайно при прив'язці. Він чекає, поки життєвий цикл досягне стану STARTED, що відповідає часу Activity.onStart().
Що відбувається, коли прив'язуються несумісні випадки використання?
Не всі комбінації випадків використання працюють на всіх пристроях. Preview + VideoCapture + ImageAnalysis + ImageCapture може не працювати на старішому обладнанні. CameraX викидає IllegalArgumentException під час прив'язки, а не під час виконання.
Рішення — перевірка CameraProvider.hasCamera() та можливостей пристрою перед прив'язкою складних комбінацій. Для критичних додатків явно тестуйте на пристроях низького класу.
Поясніть різницю між CAPTURE_MODE_MINIMIZE_LATENCY та CAPTURE_MODE_MAXIMIZE_QUALITY
MINIMIZE_LATENCY зменшує затримку затвора шляхом використання швидших конвеєрів обробки, можливо пропускаючи деяку пост-обробку. MAXIMIZE_QUALITY застосовує повну обробку HDR+, зменшення шуму та багатокадрове захоплення на підтримуваних пристроях.
Компроміс: режим затримки захоплює за 100-200мс, режим якості може займати 500мс-1с залежно від освітлення. Соціальні додатки зазвичай обирають затримку. Додатки для сканування документів обирають якість.
Як CameraX обробляє обертання пристрою?
CameraX автоматично обробляє обертання через налаштування цільового обертання. За замовчуванням використовує обертання дисплея, але додатки можуть перевизначити за допомогою setTargetRotation(). Дані EXIF вихідного зображення містять правильний тег орієнтації.
Для PreviewView, scaleType обробляє відмінності співвідношення сторін. FILL_CENTER обрізає для заповнення, FIT_CENTER показує letterboxing. Вибір залежить від того, чи додаток пріоритезує повноекранний попередній перегляд чи уникнення обрізки.
Залежності та Налаштування для CameraX 1.6
Бібліотека CameraX розділена на кілька артефактів. Додавайте лише те, що використовує додаток, щоб мінімізувати розмір 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
}
}Маніфест потребує оголошень функцій та дозволів:
<!-- 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>Пов'язані шаблони для Kotlin Coroutines застосовуються при обгортанні викликів CameraX ListenableFuture у suspend функції.
Починай практикувати!
Перевір свої знання з нашими симуляторами співбесід та технічними тестами.
Що CameraX 1.6 Змінює для Продакшн Додатків
CameraX 1.6 приніс три зміни, що впливають на існуючі реалізації:
-
Бекенд CameraPipe: Внутрішній стек камери тепер використовує CameraPipe, ту саму архітектуру, що й камера Pixel. Це покращує продуктивність на пристроях Pixel та забезпечує чистішу основу для розширених функцій. Існуючий код не потребує змін.
-
Media3 Muxer за замовчуванням: VideoCapture тепер використовує Media3 Muxer замість MediaMuxer. Це покращує стійкість до збоїв: якщо додаток завершується під час запису, відеофайл залишається відтворюваним. Поверхня API не змінилася.
-
Стабільний API SessionConfig: Додатки тепер можуть налаштовувати розширені параметри камери через SessionConfig без експериментальних анотацій. Це дозволяє такі функції, як одночасне використання передньої та задньої камери на підтримуваних пристроях.
Шлях міграції: Оновіть версію залежності. Протестуйте на пристроях, що раніше мали проблеми. Примітки до випуску CameraX документують будь-які зміни поведінки між версіями.
- CameraX використовує прив'язку, що враховує життєвий цикл:
bindToLifecycle()з'єднує випадки використання як з камерою, так і з життєвим циклом Activity - Режими ImageCapture обмінюють затримку на якість: обирайте на основі випадку використання, а не можливостей пристрою
- VideoCapture вимагає налаштування Recorder перед прив'язкою: підготуйте параметри виводу перед початком
- Обробка дозволів повинна пояснювати мету перед запитом: зменшує рівень відмов
- CameraX 1.6 внутрішньо мігрував на CameraPipe: зміни API не потрібні, але тестуйте на цільових пристроях
- Питання для співбесід зосереджуються на керуванні життєвим циклом, комбінаціях випадків використання та порівнянні з Camera2
Чи знайдеш ти помилку в Android?
Справжній фрагмент коду, прихована помилка, одна спроба на день. Щоб спробувати, акаунт не потрібен.

Автор:
Anthony Fillion-MailletЗасновник SharpSkill
Fullstack-розробник понад 10 років. Керує SharpSkill і відповідає за все, що тут публікується.
Оновлено 11 вересня 2026 р.
Поділитися
Пов'язані статті

Модуляризація Android у 2026 році: Multi-Module архітектура та питання на співбесідах
Посібник з модуляризації Android-додатків у 2026 році. Багатомодульна архітектура, Convention Plugins, Version Catalogs та питання на співбесідах для Kotlin-розробників.

Jetpack Navigation Compose у 2026: Type-Safe Навігація та Питання на Співбесіді
Комплексний посібник з Jetpack Navigation Compose з type-safe навігацією, розширеними патернами та питаннями для співбесід Android-розробників.

Android WorkManager у 2026: Фонові Завдання, Обмеження та Питання на Співбесіду
Повний посібник з WorkManager 2.11 на Kotlin - від базового налаштування через обмеження та ланцюги завдань до тестування та питань на технічних співбесідах.